DESeq2 analysis of peak universe (joint peak set called in any
condition, must be called in all three replicates, MACS3)
bw_dir <- "/Volumes/DATA/DATA/Puck/bigwig/"
chromhmm <- "../genome/ESC_10_segments.mm39.bed"
library("wigglescout")
library("ggpubr")
Loading required package: ggplot2
library("ggplot2")
library("DESeq2")
Loading required package: S4Vectors
Warning: package ‘S4Vectors’ was built under R version 4.2.2Loading required package: stats4
Loading required package: BiocGenerics
Attaching package: ‘BiocGenerics’
The following objects are masked from ‘package:stats’:
IQR, mad, sd, var, xtabs
The following objects are masked from ‘package:base’:
anyDuplicated, aperm, append, as.data.frame,
basename, cbind, colnames, dirname, do.call,
duplicated, eval, evalq, Filter, Find, get, grep,
grepl, intersect, is.unsorted, lapply, Map, mapply,
match, mget, order, paste, pmax, pmax.int, pmin,
pmin.int, Position, rank, rbind, Reduce, rownames,
sapply, setdiff, sort, table, tapply, union, unique,
unsplit, which.max, which.min
Attaching package: ‘S4Vectors’
The following objects are masked from ‘package:base’:
expand.grid, I, unname
Loading required package: IRanges
Loading required package: GenomicRanges
Warning: package ‘GenomicRanges’ was built under R version 4.2.2Loading required package: GenomeInfoDb
Warning: package ‘GenomeInfoDb’ was built under R version 4.2.2Loading required package: SummarizedExperiment
Loading required package: MatrixGenerics
Loading required package: matrixStats
Attaching package: ‘MatrixGenerics’
The following objects are masked from ‘package:matrixStats’:
colAlls, colAnyNAs, colAnys, colAvgsPerRowSet,
colCollapse, colCounts, colCummaxs, colCummins,
colCumprods, colCumsums, colDiffs, colIQRDiffs,
colIQRs, colLogSumExps, colMadDiffs, colMads,
colMaxs, colMeans2, colMedians, colMins,
colOrderStats, colProds, colQuantiles, colRanges,
colRanks, colSdDiffs, colSds, colSums2,
colTabulates, colVarDiffs, colVars, colWeightedMads,
colWeightedMeans, colWeightedMedians,
colWeightedSds, colWeightedVars, rowAlls, rowAnyNAs,
rowAnys, rowAvgsPerColSet, rowCollapse, rowCounts,
rowCummaxs, rowCummins, rowCumprods, rowCumsums,
rowDiffs, rowIQRDiffs, rowIQRs, rowLogSumExps,
rowMadDiffs, rowMads, rowMaxs, rowMeans2,
rowMedians, rowMins, rowOrderStats, rowProds,
rowQuantiles, rowRanges, rowRanks, rowSdDiffs,
rowSds, rowSums2, rowTabulates, rowVarDiffs,
rowVars, rowWeightedMads, rowWeightedMeans,
rowWeightedMedians, rowWeightedSds, rowWeightedVars
Loading required package: Biobase
Welcome to Bioconductor
Vignettes contain introductory material; view with
'browseVignettes()'. To cite Bioconductor, see
'citation("Biobase")', and for packages
'citation("pkgname")'.
Attaching package: ‘Biobase’
The following object is masked from ‘package:MatrixGenerics’:
rowMedians
The following objects are masked from ‘package:matrixStats’:
anyMissing, rowMedians
library("dplyr")
Attaching package: ‘dplyr’
The following object is masked from ‘package:Biobase’:
combine
The following object is masked from ‘package:matrixStats’:
count
The following objects are masked from ‘package:GenomicRanges’:
intersect, setdiff, union
The following object is masked from ‘package:GenomeInfoDb’:
intersect
The following objects are masked from ‘package:IRanges’:
collapse, desc, intersect, setdiff, slice, union
The following objects are masked from ‘package:S4Vectors’:
first, intersect, rename, setdiff, setequal, union
The following objects are masked from ‘package:BiocGenerics’:
combine, intersect, setdiff, union
The following objects are masked from ‘package:stats’:
filter, lag
The following objects are masked from ‘package:base’:
intersect, setdiff, setequal, union
library("ggrastr")
library("reshape2")
clean <- function (fn) {
fn <- gsub(pattern = ".+/", "", x = fn)
fn <- gsub(pattern = ".mm9.+", "", x = fn)
fn <- gsub(pattern = ".mm39.+", "", x = fn)
fn <- gsub(pattern = "_S.+", "", x = fn)
fn <- gsub(pattern = ".scaled.bw", "", x = fn)
fn <- gsub(pattern = ".unscaled.bw", "", x = fn)
fn <- gsub(pattern = "_batch2", "", x = fn)
fn <- gsub(pattern = "-", " ", x = fn)
fn <- gsub(pattern = "_", " ", x = fn)
fn <- gsub(pattern = " HA ", " ", x = fn)
fn <- gsub(pattern = "D1D6", "FANCJ-/-", x = fn)
fn <- gsub(pattern = "P2D2", "DHX36-/-", x = fn)
fn <- gsub(pattern = "P3D4", "FANCJ-/-DHX36-/-", x = fn)
return(fn)
}
BWs <- paste0(bw_dir,list.files(bw_dir,pattern="G4_.+R.\\.bw"))
mypal <-c("cornflowerblue","orange","red2","#505050")
mypal3 <-c("cornflowerblue","cornflowerblue","cornflowerblue","orange","orange","orange","red2","red2","red2","505050","505050","505050")
bw_granges_diff_analysis <- function(granges_c1,
granges_c2,
label_c1,
label_c2,
estimate_size_factors = FALSE,
as_granges = FALSE) {
# Bind first, get numbers after
names_values <- NULL
fields <- names(mcols(granges_c1))
if ("name" %in% fields) {
names_values <- mcols(granges_c1)[["name"]]
granges_c1 <- granges_c1[, fields[fields != "name"]]
}
fields <- names(mcols(granges_c2))
if ("name" %in% fields) {
granges_c2 <- granges_c2[, fields[fields != "name"]]
}
cts_df <- cbind(data.frame(granges_c1), mcols(granges_c2))
if (! is.null(names_values)) {
rownames(cts_df) <- names_values
}
# Needs to drop non-complete cases and match rows
complete <- complete.cases(cts_df)
cts_df <- cts_df[complete, ]
values_df <- cts_df[, 6:ncol(cts_df)] %>% dplyr::select(where(is.numeric))
cts <- get_nreads_columns(values_df)
condition_labels <- c(rep(label_c1, length(mcols(granges_c1))),
rep(label_c2, length(mcols(granges_c2))))
coldata <- data.frame(colnames(cts), condition = as.factor(condition_labels))
dds <- DESeq2::DESeqDataSetFromMatrix(countData = cts,
colData = coldata,
design = ~ condition,
rowRanges = granges_c1[complete, ])
if (estimate_size_factors == TRUE) {
dds <- DESeq2::estimateSizeFactors(dds)
}
else {
# Since files are scaled, we do not want to estimate size factors
sizeFactors(dds) <- c(rep(1, ncol(cts)))
}
dds <- DESeq2::estimateDispersions(dds)
dds <- DESeq2::nbinomWaldTest(dds)
if (as_granges) {
result <- DESeq2::results(dds, format = "GRanges",alpha = 0.01)
if (!is.null(names_values)) {
result$name <- names_values[complete]
}
}
else {
# result <- results(dds, format="DataFrame")
result <- dds
}
result
}
get_nreads_columns <- function(df, length_factor = 100) {
# Convert mean coverages to round integer read numbers
cts <- as.matrix(df)
cts <- as.matrix(cts[complete.cases(cts),])
cts <- round(cts*length_factor)
cts
}
peak_universe <- "../peaks/G4_combined_min3rep.bed"
BWs.WT <- BWs[grep("WT",BWs)]
BWs.FANCJ <- BWs[grep("D1D6",BWs)]
BWs.DHX36 <- BWs[grep("P2D2",BWs)]
BWs.DKO <- BWs[grep("P3D4",BWs)]
# Calculate here some loci or bins
cov.WT <- bw_loci(BWs.WT, loci = peak_universe)
Attaching package: ‘purrr’
The following object is masked from ‘package:GenomicRanges’:
reduce
The following object is masked from ‘package:IRanges’:
reduce
cov.DHX36 <- bw_loci(BWs.DHX36, loci = peak_universe)
cov.FANCJ <- bw_loci(BWs.FANCJ, loci = peak_universe)
cov.DKO <- bw_loci(BWs.DKO, loci = peak_universe)
cov.WT$name <- paste0("peak_",1:length(cov.WT))
cov.DHX36$name <- paste0("peak_",1:length(cov.DHX36))
cov.FANCJ$name <- paste0("peak_",1:length(cov.FANCJ))
cov.DKO$name <- paste0("peak_",1:length(cov.DKO))
diff_DHX36 <- bw_granges_diff_analysis(cov.WT, cov.DHX36,
"WT", "DHX36KO")
converting counts to integer mode
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
diff_FANCJ <- bw_granges_diff_analysis(cov.WT, cov.FANCJ,
"WT", "FANCJ")
converting counts to integer mode
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
diff_DKO <- bw_granges_diff_analysis(cov.WT, cov.DKO,
"WT", "DKO")
converting counts to integer mode
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
# This takes care of low conts and things like this, but you can also use
# diff_results as is for the things below
lfc_DHX36 <- DESeq2::lfcShrink(diff_DHX36, coef = "condition_WT_vs_DHX36KO", type="apeglm")
using 'apeglm' for LFC shrinkage. If used in published research, please cite:
Zhu, A., Ibrahim, J.G., Love, M.I. (2018) Heavy-tailed prior distributions for
sequence count data: removing the noise and preserving large differences.
Bioinformatics. https://doi.org/10.1093/bioinformatics/bty895
lfc_FANCJ <- DESeq2::lfcShrink(diff_FANCJ, coef = "condition_WT_vs_FANCJ", type="apeglm")
using 'apeglm' for LFC shrinkage. If used in published research, please cite:
Zhu, A., Ibrahim, J.G., Love, M.I. (2018) Heavy-tailed prior distributions for
sequence count data: removing the noise and preserving large differences.
Bioinformatics. https://doi.org/10.1093/bioinformatics/bty895
lfc_DKO <- DESeq2::lfcShrink(diff_DKO, coef = "condition_WT_vs_DKO", type="apeglm")
using 'apeglm' for LFC shrinkage. If used in published research, please cite:
Zhu, A., Ibrahim, J.G., Love, M.I. (2018) Heavy-tailed prior distributions for
sequence count data: removing the noise and preserving large differences.
Bioinformatics. https://doi.org/10.1093/bioinformatics/bty895
data_DHX36 <- plotMA(lfc_DHX36, returnData = T)
data_DHX36$lfc <- -data_DHX36$lfc
data_DHX36$mean <- log10(data_DHX36$mean)
data_FANCJ <- plotMA(lfc_FANCJ, returnData = T)
data_FANCJ$lfc <- -data_FANCJ$lfc
data_FANCJ$mean <- log10(data_FANCJ$mean)
data_DKO <- plotMA(lfc_DKO, returnData = T)
data_DKO$lfc <- -data_DKO$lfc
data_DKO$mean <- log10(data_DKO$mean)
ggscatter(data_DHX36,x ="mean",y="lfc",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[1])) + geom_hline(yintercept = 0, linetype="dashed", size=0.1) + coord_cartesian(ylim=c(-5,5))
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
Please use `linewidth` instead.

plot_MA_DHX36 <- rasterize(last_plot(), layers='Point', dpi=600)
data_DHX36$cov.WT <- rowMeans(as.data.frame(cov.WT)[,6:8])
data_DHX36$cov.DHX36 <- rowMeans(as.data.frame(cov.DHX36)[,6:8])
ggscatter(data_DHX36,x ="cov.WT",y="cov.DHX36",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[1])) + scale_x_continuous(trans="log",limits = c(0.5,400)) + scale_y_continuous(trans="log",limits = c(0.5,400)) + geom_abline(slope = 1, linetype="dashed", size=0.1)

plot_XY_DHX36 <- rasterize(last_plot(), layers='Point', dpi=600)
data_DHX36$cov.WT <- rowMeans(as.data.frame(cov.WT)[,6:8])
data_DHX36$cov.DHX36 <- rowMeans(as.data.frame(cov.DHX36)[,6:8])
ggscatter(data_DHX36,x ="cov.WT",y="cov.DHX36",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[1])) + scale_x_continuous(limits = c(-10,50)) + scale_y_continuous(limits = c(-10,50)) + geom_abline(slope = 1, linetype="dashed", size=0.1)

plot_XY_DHX36_zoom <- rasterize(last_plot(), layers='Point', dpi=600)
ggscatter(data_FANCJ,x ="mean",y="lfc",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[2])) + geom_hline(yintercept = 0, linetype="dashed", size=0.1) + coord_cartesian(ylim=c(-5,5))

plot_MA_FANCJ <- rasterize(last_plot(), layers='Point', dpi=600)
data_FANCJ$cov.WT <- rowMeans(as.data.frame(cov.WT)[,6:8])
data_FANCJ$cov.FANCJ <- rowMeans(as.data.frame(cov.FANCJ)[,6:8])
ggscatter(data_FANCJ,x ="cov.WT",y="cov.FANCJ",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[2])) + geom_hline(yintercept = 0, linetype="dashed", size=0.1) + scale_x_continuous(trans="log",limits = c(0.5,400)) + scale_y_continuous(trans="log",limits = c(0.5,400)) + geom_abline(slope = 1, linetype="dashed", size=0.1)

plot_XY_FANCJ <- rasterize(last_plot(), layers='Point', dpi=600)
ggscatter(data_DKO,x ="mean",y="lfc",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[3])) + geom_hline(yintercept = 0, linetype="dashed", size=0.1) + coord_cartesian(ylim=c(-5,5))

plot_MA_DKO <- rasterize(last_plot(), layers='Point', dpi=600)
data_DKO$cov.WT <- rowMeans(as.data.frame(cov.WT)[,6:8])
data_DKO$cov.DKO <- rowMeans(as.data.frame(cov.DKO)[,6:8])
ggscatter(data_DKO,x ="cov.WT",y="cov.DKO",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[3])) + geom_hline(yintercept = 0, linetype="dashed", size=0.1) + scale_x_continuous(trans="log",limits = c(0.5,400)) + scale_y_continuous(trans="log",limits = c(0.5,400)) + geom_abline(slope = 1, linetype="dashed", size=0.1)

plot_XY_DKO <- rasterize(last_plot(), layers='Point', dpi=600)
data_DKO$lfc_DHX36 <- data_DHX36$lfc
data_DKO$lfc_FANCJ <- data_FANCJ$lfc
ggscatter(data_DKO,x ="lfc_DHX36",y="lfc",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[3]))+ geom_hline(yintercept = 0, linetype="dashed", size=0.1) + geom_vline(xintercept = 0, linetype="dashed", size=0.1) + coord_cartesian(ylim=c(-5,5), xlim=c(-5,5))

plot_LFC_DKO_vs_DHX36 <- rasterize(last_plot(), layers='Point', dpi=600)
ggscatter(data_DKO,x ="lfc_FANCJ",y="lfc",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[3]))+ geom_hline(yintercept = 0, linetype="dashed", size=0.1) + geom_vline(xintercept = 0, linetype="dashed", size=0.1) + coord_cartesian(ylim=c(-5,5), xlim=c(-5,5))

plot_LFC_DKO_vs_FANCJ <- rasterize(last_plot(), layers='Point', dpi=600)
data_DHX36$lfc_DKO <- data_DKO$lfc
ggscatter(data_DHX36,x ="lfc",y="lfc_DKO",color="isDE",size = 0.8, alpha=0.5, palette = c("gray",mypal[1]))+ geom_hline(yintercept = 0, linetype="dashed", size=0.1) + geom_vline(xintercept = 0, linetype="dashed", size=0.1) + coord_cartesian(ylim=c(-5,5), xlim=c(-5,5))

bed <- as.data.frame(cov.DHX36)[,1:3]
results_table <- data.frame(chr=bed$seqnames,start=bed$start,end=bed$end,name=cov.WT$name, baseMean=lfc_DKO$baseMean,DHX36=data_DHX36$isDE,FANCJ=data_FANCJ$isDE,DKO=data_DKO$isDE,DHX36lfc=data_DHX36$lfc,FANCJlfc=data_FANCJ$lfc,DKOlfc=data_DKO$lfc,dir=".")
results_table$nonsig <- !(results_table$DHX36 | results_table$FANCJ | results_table$DKO)
results_table$sig <- factor("lowlfc", levels=c("nonsig","lowlfc","FANCJ","DHX36","DKO"))
results_table$sig[(results_table$nonsig)] <- "nonsig"
results_table$sig[(results_table$DKO & results_table$DKOlfc>1)] <- "DKO"
results_table$sig[(results_table$DHX36 & results_table$DHX36lfc>1)] <- "DHX36"
results_table$sig[(results_table$FANCJ & results_table$FANCJlfc>1)] <- "FANCJ"
write.table(results_table,"G4_CnT_combined_peaks_DESeq_results.txt", row.names = F, col.names = T,quote = F, sep = "\t")
results_table <- read.table("G4_CnT_combined_peaks_DESeq_results.txt", header = T, sep = "\t")
results_table$sig <- factor(results_table$sig, levels=c("nonsig","lowlfc","FANCJ","DHX36","DKO"))
DHX36_bed <- results_table[(results_table$DHX36 & results_table$DHX36lfc>1),c(1,2,3,4,9,12)]
write.table(DHX36_bed,"../peaks/G4_CnT_combined_peaks_DESeq_DHX36_sig.bed", row.names = F, col.names = F,quote = F, sep = "\t")
FANCJ_bed <- results_table[(results_table$FANCJ & results_table$FANCJlfc>1),c(1,2,3,4,10,12)]
write.table(FANCJ_bed,"../peaks/G4_CnT_combined_peaks_DESeq_FANCJ_sig.bed", row.names = F, col.names = F,quote = F, sep = "\t")
DKO_bed <- results_table[(results_table$DKO & results_table$DKOlfc>1),c(1,2,3,4,11,12)]
write.table(DKO_bed,"../peaks/G4_CnT_combined_peaks_DESeq_DKO_sig.bed", row.names = F, col.names = F,quote = F, sep = "\t")
nonsig_bed <- results_table[results_table$nonsig ,c(1,2,3,4,11,12)]
write.table(nonsig_bed,"../peaks/G4_CnT_combined_peaks_DESeq_nonsig.bed", row.names = F, col.names = F,quote = F, sep = "\t")
DKO_bed_top <- results_table[(results_table$DKO==TRUE & results_table$DKOlfc>2 & results_table$baseMean > 100),c(1,2,3,4,11,12)]
write.table(DKO_bed_top,"../peaks/G4_CnT_combined_peaks_DESeq_DKO_sig_lfc_base_cutoff.bed", row.names = F, col.names = F,quote = F, sep = "\t")
write.table(cbind(results_table[,c(1,2,3)],results_table$sig,as.numeric(results_table$sig),"."),"../peaks/G4_CnT_combined_peaks_DESeq_sig_categories.bed", row.names = F, col.names = F,quote = F, sep = "\t")
library(eulerr)
v <- list(DHX36=DHX36_bed$name,FANCJ=FANCJ_bed$name,DKO=DKO_bed$name)
plot_Venn_all <- plot(euler(v),quantities=T, border="black")
plot_Venn_all

library(eulerr)
DKOneg <- results_table[(results_table$DKO==TRUE & results_table$DKOlfc< -1),c(4)]
v <- list(all=cov.WT$name,DKOneg=DKOneg,DKO=DKO_bed$name)
plot_Venn_DKO <- plot(euler(v),quantities=T)
plot_Venn_DKO

dir.create("./plots",showWarnings = F)
ggsave("plots/peaks_DESeq2_MA_DHX36.pdf",plot_MA_DHX36,width = 4, height= 4)
ggsave("plots/peaks_DESeq2_MA_FANCJ.pdf",plot_MA_FANCJ,width = 4, height= 4)
ggsave("plots/peaks_DESeq2_MA_DKO.pdf",plot_MA_DKO,width = 4, height= 4)
ggsave("plots/peaks_DESeq2_LFC_DHX36.pdf",plot_LFC_DKO_vs_DHX36,width = 4, height= 4)
ggsave("plots/peaks_DESeq2_LFC_FANCJ.pdf",plot_LFC_DKO_vs_FANCJ,width = 4, height= 4)
ggsave("plots/peaks_DESeq2_Venn_KOs.pdf",plot_Venn_all,width = 4, height= 4)
ggsave("plots/peaks_DESeq2_Venn_DKO_vs_all.pdf",plot_Venn_DKO,width = 4, height= 4)
library(cowplot)
Attaching package: ‘cowplot’
The following object is masked from ‘package:ggpubr’:
get_legend
dir.create("./panels",showWarnings = F)
library("cowplot")
p <- ggdraw() +
draw_plot(plot_MA_DHX36, x = 0, y = 0.5, width = .33, height = .5) +
draw_plot(plot_MA_FANCJ, x = .33, y = 0.5, width = .33, height = .5) +
draw_plot(plot_MA_DKO, x = 0.66, y = 0.5, width = .33, height = 0.5) +
draw_plot(plot_LFC_DKO_vs_DHX36, x = 0, y = 0, width = 0.33, height = 0.5) +
draw_plot(plot_LFC_DKO_vs_FANCJ, x = 0.33, y = 0, width = 0.33, height = 0.5) +
draw_plot(plot_Venn_all, x = 0.66, y = 0, width = 0.33, height = 0.5) +
draw_plot_label(label = c("a", "b", "c","d","e","f"), size = 15,
x = c(0, 0.33, 0.66, 0, 0.33, 0.66), y = c(1, 1, 1, 0.5, 0.5, 0.5))
p

ggsave("panels/peaks_DESeq2.pdf",p)
Saving 12 x 8 in image

cov <- cbind( as.data.frame(cov.WT)[,1:8],
as.data.frame(cov.DHX36)[,6:8],
as.data.frame(cov.FANCJ)[,6:8],
as.data.frame(cov.DKO)[,6:8])
colnames(cov) <- c(colnames(cov)[1:5],"WT1","WT2","WT3","DHX1","DHX2","DHX3","FAN1","FAN2","FAN3","DKO1","DKO2","DKO3")
rownames(cov) <- as.data.frame(cov.WT)$name
cov$DHX36_sig <- rownames(cov) %in% DHX36_bed$name
cov$FANCJ_sig <- rownames(cov) %in% FANCJ_bed$name
cov$DKO_sig <- rownames(cov) %in% DKO_bed$name
cov$non_sig <- with(cov, !(DHX36_sig | FANCJ_sig | DKO_sig))
library(reshape2)
mdf <- melt(data.frame(name=rownames(cov),cov[,6:21]))
Using name, DHX36_sig, FANCJ_sig, DKO_sig, non_sig as id variables
mdf <- mdf[mdf$value<500,]
mdf$cond <- "WT"
mdf$cond[grep("DHX",mdf$variable)] <- "DHX36-/-"
mdf$cond[grep("FAN",mdf$variable)] <- "FANCJ-/-"
mdf$cond[grep("DKO",mdf$variable)] <- "DHX36-/-FANCJ-/-"
plot_viol_rep_all_peaks <- ggviolin(mdf, x="variable",y="value",fill="cond",palette = mypal, add="mean_sd") +
coord_cartesian(ylim=c(0,50))
plot_viol_rep_all_peaks

plot_viol_rep_DHX36_peaks <- ggviolin(mdf[mdf$DHX36_sig,], x="variable",y="value",fill="cond",palette = mypal, add="mean_sd") +
coord_cartesian(ylim=c(0,50))
plot_viol_rep_DHX36_peaks

ggviolin(mdf[mdf$FANCJ_sig,], x="variable",y="value",fill="cond",palette = mypal, add="mean_sd") +
coord_cartesian(ylim=c(0,50))

plot_viol_rep_DKO_peaks <- ggviolin(mdf[mdf$DKO_sig,], x="variable",y="value",fill="cond",palette = mypal, add="mean_sd") +
coord_cartesian(ylim=c(0,50))
plot_viol_rep_DKO_peaks

plot_viol_rep_nonsig_peaks <- ggviolin(mdf[mdf$non_sig,], x="variable",y="value",fill="cond",palette = mypal, add="mean_sd") +
coord_cartesian(ylim=c(0,50))
plot_viol_rep_nonsig_peaks

ggsave("plots/peaks_DESeq2_viol_rep_all.pdf",plot_viol_rep_all_peaks)
Saving 7 x 7 in image
ggsave("plots/peaks_DESeq2_viol_rep_DKO.pdf",plot_viol_rep_DKO_peaks)
ggsave("plots/peaks_DESeq2_viol_rep_DHX36.pdf",plot_viol_rep_DHX36_peaks)
ggsave("plots/peaks_DESeq2_viol_rep_nonsig.pdf",plot_viol_rep_nonsig_peaks)
sdf <- aggregate(value ~ name + cond, data=mdf, FUN="mean")
sdf$cond <- factor(sdf$cond,levels=c("WT","DHX36-/-","FANCJ-/-","DHX36-/-FANCJ-/-"))
ggviolin(sdf, x="cond",y="value",fill="cond",palette = mypal[c(4,1,2,3)], add="mean_sd") +
coord_cartesian(ylim=c(0,50))

sdf$DHX36_sig <- sdf$name %in% DHX36_bed$name
sdf$FANCJ_sig <- sdf$name %in% FANCJ_bed$name
sdf$DKO_sig <- sdf$name %in% DKO_bed$name
sdf$DKO_top <- sdf$name %in% DKO_bed_top$name
ggviolin(sdf[sdf$DHX36,], x="cond",y="value",fill="cond",palette = mypal[c(4,1,2,3)], add="mean_sd") +
coord_cartesian(ylim=c(0,75))

ggviolin(sdf[sdf$FANCJ_sig,], x="cond",y="value",fill="cond",palette = mypal[c(4,1,2,3)], add="mean_sd") +
coord_cartesian(ylim=c(0,75))

plot_viol_DKO_peaks <- ggviolin(sdf[sdf$DKO_sig,], x="cond",y="value",fill="cond",palette = mypal[c(4,1,2,3)], add="mean_sd") +
coord_cartesian(ylim=c(0,75))
plot_viol_DKO_peaks

ggviolin(sdf[sdf$DKO_top,], x="cond",y="value",fill="cond",palette = mypal[c(4,1,2,3)], add="mean_sd") +
coord_cartesian(ylim=c(0,75))

non-DJ Peak Annotation
bed_nonDJ <- bed_peaks_table[bed_peaks_table$nonsig,c(1,2,3,6,16,5)]
bed_nonDJ$name <- "nonDJ"
write.table(bed_nonDJ,"../peaks/G4_CnT_combined_peaks_nonDJ.bed", row.names = F, col.names = F,quote = F, sep = "\t")
bed_DJ$DKOlfc <- 1
bed_nonDJ$DKOlfc <- 0
write.table(rbind(bed_DJ,bed_nonDJ),"../peaks/G4_CnT_combined_peaks_DJ_nonDJ.bed", row.names = F, col.names = F,quote = F, sep = "\t")
stats <- as.data.frame(table(bed_peaks_table$feature[bed_peaks_table$nonsig]))
plot_donut_nonDJ <- ggdonutchart(stats,x = "Freq",label="Var1",fill=vpal(10))
plot_donut_nonDJ

ggsave("plots/plot_donut_DJ.pdf",plot_donut_DJ)
Saving 7 x 7 in image
ggsave("plots/plot_donut_nonDJ.pdf",plot_donut_nonDJ)
ggsave("plots/plot_donut_all.pdf",plot_donut_all)
vpal=colorRampPalette(c("lightgreen","cornflowerblue","orange","red2"))
stats <- data.frame(as.data.frame(table(bed_peaks_table$feature))[1],as.data.frame(table(bed_peaks_table$feature[bed_peaks_table$DKO]))[2],as.data.frame(table(bed_peaks_table$feature[bed_peaks_table$nonsig]))[2])
colnames(stats) <- c("State","DJ","nonDJ")
#stats$DHX36=stats$DJ/sum(stats$DJ)*100
#stats$FANCJ=stats$nonDJ/sum(stats$nonDJ)*100
mdf <- melt(stats)
Using State as id variables
mdf$State <- factor(mdf$State,levels=levels(mdf$State)[c(1,3,5,7,4,6,10,8,9,2)])
cols=c(vpal(11)[c(4,5,3,2,9,8,7)],"#DDDDDD","#EEEEEE",vpal(11)[10])
plot_bar_chromhmm_anno <- ggbarplot(mdf,x = "variable",y="value",fill="State",palette =cols, orientation = c("horizontal"))
plot_bar_chromhmm_anno

vpal=colorRampPalette(c("lightgreen","cornflowerblue","orange","red2"))
stats <- data.frame(as.data.frame(table(bed_peaks_table$feature))[1],as.data.frame(table(bed_peaks_table$feature))[2],as.data.frame(table(bed_peaks_table$feature[bed_peaks_table$DKO]))[2],as.data.frame(table(bed_peaks_table$feature[bed_peaks_table$nonsig]))[2])
colnames(stats) <- c("State","all","DJ","nonDJ")
#stats$DHX36=stats$DJ/sum(stats$DJ)*100
#stats$FANCJ=stats$nonDJ/sum(stats$nonDJ)*100
mdf <- melt(stats)
Using State as id variables
mdf$State <- factor(mdf$State,levels=levels(mdf$State)[c(1,3,5,7,4,6,10,8,9,2)])
cols=c(vpal(11)[c(4,5,3,2,9,8,7)],"#DDDDDD","#EEEEEE",vpal(11)[10])
plot_bar_chromhmm_anno_all <- ggbarplot(mdf,x = "variable",y="value",fill="State",palette =cols, orientation = c("horizontal"))
plot_bar_chromhmm_anno_all

stats$DJ=stats$DJ/sum(stats$DJ)*100
stats$nonDJ=stats$nonDJ/sum(stats$nonDJ)*100
stats$all=stats$all/sum(stats$all)*100
mdf <- melt(stats)
Using State as id variables
mdf$State <- factor(mdf$State,levels=levels(mdf$State)[c(1,3,5,7,4,6,10,8,9,2)])
cols=c(vpal(11)[c(4,5,3,2,9,8,7)],"#DDDDDD","#EEEEEE",vpal(11)[10])
plot_bar_chromhmm_anno_norm <- ggbarplot(mdf,x = "variable",y="value",fill="State",palette =cols, orientation = c("horizontal"))
plot_bar_chromhmm_anno_norm

ggsave("plots/plot_bar_chromhmm.pdf",plot_bar_chromhmm_anno)
Saving 7 x 7 in image
ggsave("plots/plot_bar_chromhmm_rel.pdf",plot_bar_chromhmm_anno_norm)
vpal=colorRampPalette(c("lightgreen","cornflowerblue","orange","red2"))
stats <- data.frame(as.data.frame(table(bed_peaks_table$feature)),DHX36=as.data.frame(table(bed_peaks_table$feature[bed_peaks_table$DHX36==TRUE]))[2],FANCJ=as.data.frame(table(bed_peaks_table$feature[bed_peaks_table$FANCJ==TRUE]))[2],DKO=as.data.frame(table(bed_peaks_table$feature[bed_peaks_table$DKO==TRUE]))[2])
colnames(stats) <- c("State","Total","DHX36","FANCJ","DKO")
stats$Total=stats$Total/sum(stats$Total)*100
stats$DHX36=stats$DHX36/sum(stats$DHX36)*100
stats$FANCJ=stats$FANCJ/sum(stats$FANCJ)*100
stats$DKO=stats$DKO/sum(stats$DKO)*100
mdf <- melt(stats)
Using State as id variables
mdf$State <- factor(mdf$State,levels=levels(mdf$State)[c(1,3,5,7,4,6,10,8,9,2)])
cols=c(vpal(11)[c(4,5,3,2,9,8,7)],"#DDDDDD","#EEEEEE",vpal(11)[10])
plot_bar_chromhmm_anno <- ggbarplot(mdf,x = "variable",y="value",fill="State",palette =cols,label=mdf$State)
plot_bar_chromhmm_anno

p <- ggdraw() +
draw_plot(plot_bar_chromhmm_anno, x = 0, y = 0, width = .20, height = 1) +
draw_plot(plot_viol_rep_DKO_peaks, x = .2, y = 0, width = .40, height = 0.7) +
draw_plot(plot_viol_rep_nonsig_peaks, x = 0.6, y = 0, width = .40, height = 0.7) +
draw_plot_label(label = c("a", "b", "c"), size = 15,
x = c(0, 0.2, 0.6), y = c(1, 0.8, 0.8))
p

ggsave("panels/peak_anno_violin_v1.pdf",p)
Saving 16 x 6 in image
p <- ggdraw() +
draw_plot(plot_bar_chromhmm_anno, x = 0, y = 0, width = .4, height = 1) +
draw_plot(plot_viol_rep_DKO_peaks, x = .4, y = 0.5, width = .60, height = 0.5) +
draw_plot(plot_viol_rep_nonsig_peaks, x = 0.4, y = 0, width = .60, height = 0.5) +
draw_plot_label(label = c("a", "b", "c"), size = 15,
x = c(0, 0.4, 0.4), y = c(1, 1, 0.5))
p

ggsave("panels/peak_anno_violin_v2.pdf",p)
Saving 16 x 6 in image
LS0tCnRpdGxlOiAiRzQgQ1VUJlRhZyBhbmFseXNpcyBtRVNDIChXVCwgRkFOQ0ogS08sIERIWDM2IEtPLCBES08pIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpTaW1vbiBFbHPDpHNzZXIsIEthcm9saW5za2EgSW5zdGl0dXRldCAoMjAyMykKCiMjIyBERVNlcTIgYW5hbHlzaXMgb2YgcGVhayB1bml2ZXJzZSAoam9pbnQgcGVhayBzZXQgY2FsbGVkIGluIGFueSBjb25kaXRpb24sIG11c3QgYmUgY2FsbGVkIGluIGFsbCB0aHJlZSByZXBsaWNhdGVzLCBNQUNTMykKCgpgYGB7ciBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD0zfQpid19kaXIgPC0gIi9Wb2x1bWVzL0RBVEEvREFUQS9QdWNrL2JpZ3dpZy8iCmNocm9taG1tIDwtICIuLi9nZW5vbWUvRVNDXzEwX3NlZ21lbnRzLm1tMzkuYmVkIgoKbGlicmFyeSgid2lnZ2xlc2NvdXQiKQpsaWJyYXJ5KCJnZ3B1YnIiKQpsaWJyYXJ5KCJnZ3Bsb3QyIikKbGlicmFyeSgiREVTZXEyIikKbGlicmFyeSgiZHBseXIiKQpsaWJyYXJ5KCJnZ3Jhc3RyIikKbGlicmFyeSgicmVzaGFwZTIiKQoKY2xlYW4gPC0gZnVuY3Rpb24gKGZuKSB7CiAgZm4gPC0gZ3N1YihwYXR0ZXJuID0gIi4rLyIsICIiLCB4ID0gZm4pCiAgZm4gPC0gZ3N1YihwYXR0ZXJuID0gIi5tbTkuKyIsICIiLCB4ID0gZm4pCiAgZm4gPC0gZ3N1YihwYXR0ZXJuID0gIi5tbTM5LisiLCAiIiwgeCA9IGZuKQogIGZuIDwtIGdzdWIocGF0dGVybiA9ICJfUy4rIiwgIiIsIHggPSBmbikKICBmbiA8LSBnc3ViKHBhdHRlcm4gPSAiLnNjYWxlZC5idyIsICIiLCB4ID0gZm4pCiAgZm4gPC0gZ3N1YihwYXR0ZXJuID0gIi51bnNjYWxlZC5idyIsICIiLCB4ID0gZm4pCiAgZm4gPC0gZ3N1YihwYXR0ZXJuID0gIl9iYXRjaDIiLCAiIiwgeCA9IGZuKQogIGZuIDwtIGdzdWIocGF0dGVybiA9ICItIiwgIiAiLCB4ID0gZm4pCiAgZm4gPC0gZ3N1YihwYXR0ZXJuID0gIl8iLCAiICIsIHggPSBmbikKICBmbiA8LSBnc3ViKHBhdHRlcm4gPSAiIEhBICIsICIgIiwgeCA9IGZuKQogIGZuIDwtIGdzdWIocGF0dGVybiA9ICJEMUQ2IiwgIkZBTkNKLS8tIiwgeCA9IGZuKQogIGZuIDwtIGdzdWIocGF0dGVybiA9ICJQMkQyIiwgIkRIWDM2LS8tIiwgeCA9IGZuKQogIGZuIDwtIGdzdWIocGF0dGVybiA9ICJQM0Q0IiwgIkZBTkNKLS8tREhYMzYtLy0iLCB4ID0gZm4pCiAgcmV0dXJuKGZuKQp9CgpCV3MgPC0gcGFzdGUwKGJ3X2RpcixsaXN0LmZpbGVzKGJ3X2RpcixwYXR0ZXJuPSJHNF8uK1IuXFwuYnciKSkKCm15cGFsIDwtYygiY29ybmZsb3dlcmJsdWUiLCJvcmFuZ2UiLCJyZWQyIiwiIzUwNTA1MCIpCm15cGFsMyA8LWMoImNvcm5mbG93ZXJibHVlIiwiY29ybmZsb3dlcmJsdWUiLCJjb3JuZmxvd2VyYmx1ZSIsIm9yYW5nZSIsIm9yYW5nZSIsIm9yYW5nZSIsInJlZDIiLCJyZWQyIiwicmVkMiIsIjUwNTA1MCIsIjUwNTA1MCIsIjUwNTA1MCIpCmBgYAoKYGBge3J9CmJ3X2dyYW5nZXNfZGlmZl9hbmFseXNpcyA8LSBmdW5jdGlvbihncmFuZ2VzX2MxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3Jhbmdlc19jMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsX2MxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxfYzIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlc3RpbWF0ZV9zaXplX2ZhY3RvcnMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzX2dyYW5nZXMgPSBGQUxTRSkgewoKICAjIEJpbmQgZmlyc3QsIGdldCBudW1iZXJzIGFmdGVyCiAgbmFtZXNfdmFsdWVzIDwtIE5VTEwKICBmaWVsZHMgPC0gbmFtZXMobWNvbHMoZ3Jhbmdlc19jMSkpCgogIGlmICgibmFtZSIgJWluJSBmaWVsZHMpIHsKICAgIG5hbWVzX3ZhbHVlcyA8LSBtY29scyhncmFuZ2VzX2MxKVtbIm5hbWUiXV0KICAgIGdyYW5nZXNfYzEgPC0gZ3Jhbmdlc19jMVssIGZpZWxkc1tmaWVsZHMgIT0gIm5hbWUiXV0KICB9CgogIGZpZWxkcyA8LSBuYW1lcyhtY29scyhncmFuZ2VzX2MyKSkKICBpZiAoIm5hbWUiICVpbiUgZmllbGRzKSB7CiAgICBncmFuZ2VzX2MyIDwtIGdyYW5nZXNfYzJbLCBmaWVsZHNbZmllbGRzICE9ICJuYW1lIl1dCiAgfQoKICBjdHNfZGYgPC0gY2JpbmQoZGF0YS5mcmFtZShncmFuZ2VzX2MxKSwgbWNvbHMoZ3Jhbmdlc19jMikpCgogIGlmICghIGlzLm51bGwobmFtZXNfdmFsdWVzKSkgewogICAgcm93bmFtZXMoY3RzX2RmKSA8LSBuYW1lc192YWx1ZXMKICB9CgogICMgTmVlZHMgdG8gZHJvcCBub24tY29tcGxldGUgY2FzZXMgYW5kIG1hdGNoIHJvd3MKICBjb21wbGV0ZSA8LSBjb21wbGV0ZS5jYXNlcyhjdHNfZGYpCiAgY3RzX2RmIDwtIGN0c19kZltjb21wbGV0ZSwgXQoKICB2YWx1ZXNfZGYgPC0gY3RzX2RmWywgNjpuY29sKGN0c19kZildICU+JSBkcGx5cjo6c2VsZWN0KHdoZXJlKGlzLm51bWVyaWMpKQogIGN0cyA8LSBnZXRfbnJlYWRzX2NvbHVtbnModmFsdWVzX2RmKQoKICBjb25kaXRpb25fbGFiZWxzIDwtIGMocmVwKGxhYmVsX2MxLCBsZW5ndGgobWNvbHMoZ3Jhbmdlc19jMSkpKSwKICAgICAgICAgICAgICAgICAgICAgICAgcmVwKGxhYmVsX2MyLCBsZW5ndGgobWNvbHMoZ3Jhbmdlc19jMikpKSkKCgogIGNvbGRhdGEgPC0gZGF0YS5mcmFtZShjb2xuYW1lcyhjdHMpLCBjb25kaXRpb24gPSBhcy5mYWN0b3IoY29uZGl0aW9uX2xhYmVscykpCgogIGRkcyA8LSBERVNlcTI6OkRFU2VxRGF0YVNldEZyb21NYXRyaXgoY291bnREYXRhID0gY3RzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbERhdGEgPSBjb2xkYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2lnbiA9IH4gY29uZGl0aW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd1JhbmdlcyA9IGdyYW5nZXNfYzFbY29tcGxldGUsIF0pCgoKICBpZiAoZXN0aW1hdGVfc2l6ZV9mYWN0b3JzID09IFRSVUUpIHsKICAgIGRkcyA8LSBERVNlcTI6OmVzdGltYXRlU2l6ZUZhY3RvcnMoZGRzKQogIH0KICBlbHNlIHsKICAgICMgU2luY2UgZmlsZXMgYXJlIHNjYWxlZCwgd2UgZG8gbm90IHdhbnQgdG8gZXN0aW1hdGUgc2l6ZSBmYWN0b3JzCiAgICBzaXplRmFjdG9ycyhkZHMpIDwtIGMocmVwKDEsIG5jb2woY3RzKSkpCiAgfQoKICBkZHMgPC0gREVTZXEyOjplc3RpbWF0ZURpc3BlcnNpb25zKGRkcykKICBkZHMgPC0gREVTZXEyOjpuYmlub21XYWxkVGVzdChkZHMpCgogIGlmIChhc19ncmFuZ2VzKSB7CiAgICByZXN1bHQgPC0gREVTZXEyOjpyZXN1bHRzKGRkcywgZm9ybWF0ID0gIkdSYW5nZXMiLGFscGhhID0gMC4wMSkKICAgIGlmICghaXMubnVsbChuYW1lc192YWx1ZXMpKSB7CiAgICAgIHJlc3VsdCRuYW1lIDwtIG5hbWVzX3ZhbHVlc1tjb21wbGV0ZV0KICAgIH0KCiAgfQogIGVsc2UgewogICAgIyByZXN1bHQgPC0gcmVzdWx0cyhkZHMsIGZvcm1hdD0iRGF0YUZyYW1lIikKICAgIHJlc3VsdCA8LSBkZHMKICB9CgogIHJlc3VsdAp9CgpnZXRfbnJlYWRzX2NvbHVtbnMgPC0gZnVuY3Rpb24oZGYsIGxlbmd0aF9mYWN0b3IgPSAxMDApIHsKICAjIENvbnZlcnQgbWVhbiBjb3ZlcmFnZXMgdG8gcm91bmQgaW50ZWdlciByZWFkIG51bWJlcnMKICBjdHMgPC0gYXMubWF0cml4KGRmKQogIGN0cyA8LSBhcy5tYXRyaXgoY3RzW2NvbXBsZXRlLmNhc2VzKGN0cyksXSkKICBjdHMgPC0gcm91bmQoY3RzKmxlbmd0aF9mYWN0b3IpCiAgY3RzCn0KYGBgCgpgYGB7cn0KCnBlYWtfdW5pdmVyc2UgPC0gIi4uL3BlYWtzL0c0X2NvbWJpbmVkX21pbjNyZXAuYmVkIgoKQldzLldUIDwtIEJXc1tncmVwKCJXVCIsQldzKV0KQldzLkZBTkNKIDwtIEJXc1tncmVwKCJEMUQ2IixCV3MpXQpCV3MuREhYMzYgPC0gQldzW2dyZXAoIlAyRDIiLEJXcyldCkJXcy5ES08gPC0gQldzW2dyZXAoIlAzRDQiLEJXcyldCiAgCiMgQ2FsY3VsYXRlIGhlcmUgc29tZSBsb2NpIG9yIGJpbnMKY292LldUIDwtIGJ3X2xvY2koQldzLldULCBsb2NpID0gcGVha191bml2ZXJzZSkKY292LkRIWDM2IDwtIGJ3X2xvY2koQldzLkRIWDM2LCBsb2NpID0gcGVha191bml2ZXJzZSkKY292LkZBTkNKIDwtIGJ3X2xvY2koQldzLkZBTkNKLCBsb2NpID0gcGVha191bml2ZXJzZSkKY292LkRLTyA8LSBid19sb2NpKEJXcy5ES08sIGxvY2kgPSBwZWFrX3VuaXZlcnNlKQoKY292LldUJG5hbWUgPC0gcGFzdGUwKCJwZWFrXyIsMTpsZW5ndGgoY292LldUKSkKY292LkRIWDM2JG5hbWUgPC0gcGFzdGUwKCJwZWFrXyIsMTpsZW5ndGgoY292LkRIWDM2KSkKY292LkZBTkNKJG5hbWUgPC0gcGFzdGUwKCJwZWFrXyIsMTpsZW5ndGgoY292LkZBTkNKKSkKY292LkRLTyRuYW1lIDwtIHBhc3RlMCgicGVha18iLDE6bGVuZ3RoKGNvdi5ES08pKQpgYGAKCmBgYHtyfQpkaWZmX0RIWDM2IDwtIGJ3X2dyYW5nZXNfZGlmZl9hbmFseXNpcyhjb3YuV1QsIGNvdi5ESFgzNiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJXVCIsICJESFgzNktPIikKZGlmZl9GQU5DSiA8LSBid19ncmFuZ2VzX2RpZmZfYW5hbHlzaXMoY292LldULCBjb3YuRkFOQ0osCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiV1QiLCAiRkFOQ0oiKQpkaWZmX0RLTyA8LSBid19ncmFuZ2VzX2RpZmZfYW5hbHlzaXMoY292LldULCBjb3YuREtPLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIldUIiwgIkRLTyIpCgoKIyBUaGlzIHRha2VzIGNhcmUgb2YgbG93IGNvbnRzIGFuZCB0aGluZ3MgbGlrZSB0aGlzLCBidXQgeW91IGNhbiBhbHNvIHVzZQojIGRpZmZfcmVzdWx0cyBhcyBpcyBmb3IgdGhlIHRoaW5ncyBiZWxvdwpsZmNfREhYMzYgPC0gREVTZXEyOjpsZmNTaHJpbmsoZGlmZl9ESFgzNiwgY29lZiA9ICJjb25kaXRpb25fV1RfdnNfREhYMzZLTyIsIHR5cGU9ImFwZWdsbSIpCmxmY19GQU5DSiA8LSBERVNlcTI6OmxmY1NocmluayhkaWZmX0ZBTkNKLCBjb2VmID0gImNvbmRpdGlvbl9XVF92c19GQU5DSiIsIHR5cGU9ImFwZWdsbSIpCmxmY19ES08gPC0gREVTZXEyOjpsZmNTaHJpbmsoZGlmZl9ES08sIGNvZWYgPSAiY29uZGl0aW9uX1dUX3ZzX0RLTyIsIHR5cGU9ImFwZWdsbSIpCgpkYXRhX0RIWDM2IDwtIHBsb3RNQShsZmNfREhYMzYsIHJldHVybkRhdGEgPSBUKQpkYXRhX0RIWDM2JGxmYyA8LSAtZGF0YV9ESFgzNiRsZmMKZGF0YV9ESFgzNiRtZWFuIDwtIGxvZzEwKGRhdGFfREhYMzYkbWVhbikKCmRhdGFfRkFOQ0ogPC0gcGxvdE1BKGxmY19GQU5DSiwgcmV0dXJuRGF0YSA9IFQpCmRhdGFfRkFOQ0okbGZjIDwtIC1kYXRhX0ZBTkNKJGxmYwpkYXRhX0ZBTkNKJG1lYW4gPC0gbG9nMTAoZGF0YV9GQU5DSiRtZWFuKQoKZGF0YV9ES08gPC0gcGxvdE1BKGxmY19ES08sIHJldHVybkRhdGEgPSBUKQpkYXRhX0RLTyRsZmMgPC0gLWRhdGFfREtPJGxmYwpkYXRhX0RLTyRtZWFuIDwtIGxvZzEwKGRhdGFfREtPJG1lYW4pCmBgYAoKCmBgYHtyIGZpZy53aWR0aD0yLCBmaWcuaGVpZ2h0PTJ9Cmdnc2NhdHRlcihkYXRhX0RIWDM2LHggPSJtZWFuIix5PSJsZmMiLGNvbG9yPSJpc0RFIixzaXplID0gMC44LCBhbHBoYT0wLjUsIHBhbGV0dGUgPSBjKCJncmF5IixteXBhbFsxXSkpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MC4xKSArIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoLTUsNSkpCnBsb3RfTUFfREhYMzYgPC0gcmFzdGVyaXplKGxhc3RfcGxvdCgpLCBsYXllcnM9J1BvaW50JywgZHBpPTYwMCkgCmBgYApgYGB7ciBmaWcud2lkdGg9MiwgZmlnLmhlaWdodD0yfQpkYXRhX0RIWDM2JGNvdi5XVCA8LSByb3dNZWFucyhhcy5kYXRhLmZyYW1lKGNvdi5XVClbLDY6OF0pCmRhdGFfREhYMzYkY292LkRIWDM2IDwtIHJvd01lYW5zKGFzLmRhdGEuZnJhbWUoY292LkRIWDM2KVssNjo4XSkKZ2dzY2F0dGVyKGRhdGFfREhYMzYseCA9ImNvdi5XVCIseT0iY292LkRIWDM2Iixjb2xvcj0iaXNERSIsc2l6ZSA9IDAuOCwgYWxwaGE9MC41LCBwYWxldHRlID0gYygiZ3JheSIsbXlwYWxbMV0pKSArIHNjYWxlX3hfY29udGludW91cyh0cmFucz0ibG9nIixsaW1pdHMgPSBjKDAuNSw0MDApKSArIHNjYWxlX3lfY29udGludW91cyh0cmFucz0ibG9nIixsaW1pdHMgPSBjKDAuNSw0MDApKSArIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MC4xKQpwbG90X1hZX0RIWDM2IDwtIHJhc3Rlcml6ZShsYXN0X3Bsb3QoKSwgbGF5ZXJzPSdQb2ludCcsIGRwaT02MDApIApgYGAKYGBge3IgZmlnLndpZHRoPTIsIGZpZy5oZWlnaHQ9Mn0KZGF0YV9ESFgzNiRjb3YuV1QgPC0gcm93TWVhbnMoYXMuZGF0YS5mcmFtZShjb3YuV1QpWyw2OjhdKQpkYXRhX0RIWDM2JGNvdi5ESFgzNiA8LSByb3dNZWFucyhhcy5kYXRhLmZyYW1lKGNvdi5ESFgzNilbLDY6OF0pCmdnc2NhdHRlcihkYXRhX0RIWDM2LHggPSJjb3YuV1QiLHk9ImNvdi5ESFgzNiIsY29sb3I9ImlzREUiLHNpemUgPSAwLjgsIGFscGhhPTAuNSwgcGFsZXR0ZSA9IGMoImdyYXkiLG15cGFsWzFdKSkgKyBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygtMTAsNTApKSArIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKC0xMCw1MCkpICsgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0wLjEpCnBsb3RfWFlfREhYMzZfem9vbSA8LSByYXN0ZXJpemUobGFzdF9wbG90KCksIGxheWVycz0nUG9pbnQnLCBkcGk9NjAwKSAKYGBgCgpgYGB7ciBmaWcud2lkdGg9MiwgZmlnLmhlaWdodD0yfQpnZ3NjYXR0ZXIoZGF0YV9GQU5DSix4ID0ibWVhbiIseT0ibGZjIixjb2xvcj0iaXNERSIsc2l6ZSA9IDAuOCwgYWxwaGE9MC41LCBwYWxldHRlID0gYygiZ3JheSIsbXlwYWxbMl0pKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTAuMSkgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKC01LDUpKQpwbG90X01BX0ZBTkNKIDwtIHJhc3Rlcml6ZShsYXN0X3Bsb3QoKSwgbGF5ZXJzPSdQb2ludCcsIGRwaT02MDApIApgYGAKCmBgYHtyIGZpZy53aWR0aD0yLCBmaWcuaGVpZ2h0PTJ9CmRhdGFfRkFOQ0okY292LldUIDwtIHJvd01lYW5zKGFzLmRhdGEuZnJhbWUoY292LldUKVssNjo4XSkKZGF0YV9GQU5DSiRjb3YuRkFOQ0ogPC0gcm93TWVhbnMoYXMuZGF0YS5mcmFtZShjb3YuRkFOQ0opWyw2OjhdKQpnZ3NjYXR0ZXIoZGF0YV9GQU5DSix4ID0iY292LldUIix5PSJjb3YuRkFOQ0oiLGNvbG9yPSJpc0RFIixzaXplID0gMC44LCBhbHBoYT0wLjUsIHBhbGV0dGUgPSBjKCJncmF5IixteXBhbFsyXSkpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MC4xKSArIHNjYWxlX3hfY29udGludW91cyh0cmFucz0ibG9nIixsaW1pdHMgPSBjKDAuNSw0MDApKSArIHNjYWxlX3lfY29udGludW91cyh0cmFucz0ibG9nIixsaW1pdHMgPSBjKDAuNSw0MDApKSArIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MC4xKQpwbG90X1hZX0ZBTkNKIDwtIHJhc3Rlcml6ZShsYXN0X3Bsb3QoKSwgbGF5ZXJzPSdQb2ludCcsIGRwaT02MDApIApgYGAKCmBgYHtyIGZpZy53aWR0aD0yLCBmaWcuaGVpZ2h0PTJ9Cmdnc2NhdHRlcihkYXRhX0RLTyx4ID0ibWVhbiIseT0ibGZjIixjb2xvcj0iaXNERSIsc2l6ZSA9IDAuOCwgYWxwaGE9MC41LCBwYWxldHRlID0gYygiZ3JheSIsbXlwYWxbM10pKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTAuMSkgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKC01LDUpKQpwbG90X01BX0RLTyA8LSByYXN0ZXJpemUobGFzdF9wbG90KCksIGxheWVycz0nUG9pbnQnLCBkcGk9NjAwKSAKYGBgCgpgYGB7ciBmaWcud2lkdGg9MiwgZmlnLmhlaWdodD0yfQpkYXRhX0RLTyRjb3YuV1QgPC0gcm93TWVhbnMoYXMuZGF0YS5mcmFtZShjb3YuV1QpWyw2OjhdKQpkYXRhX0RLTyRjb3YuREtPIDwtIHJvd01lYW5zKGFzLmRhdGEuZnJhbWUoY292LkRLTylbLDY6OF0pCmdnc2NhdHRlcihkYXRhX0RLTyx4ID0iY292LldUIix5PSJjb3YuREtPIixjb2xvcj0iaXNERSIsc2l6ZSA9IDAuOCwgYWxwaGE9MC41LCBwYWxldHRlID0gYygiZ3JheSIsbXlwYWxbM10pKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTAuMSkgKyBzY2FsZV94X2NvbnRpbnVvdXModHJhbnM9ImxvZyIsbGltaXRzID0gYygwLjUsNDAwKSkgKyBzY2FsZV95X2NvbnRpbnVvdXModHJhbnM9ImxvZyIsbGltaXRzID0gYygwLjUsNDAwKSkgKyBnZW9tX2FibGluZShzbG9wZSA9IDEsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTAuMSkKcGxvdF9YWV9ES08gPC0gcmFzdGVyaXplKGxhc3RfcGxvdCgpLCBsYXllcnM9J1BvaW50JywgZHBpPTYwMCkgCmBgYAoKYGBge3IgZmlnLndpZHRoPTIsIGZpZy5oZWlnaHQ9Mn0KZGF0YV9ES08kbGZjX0RIWDM2IDwtIGRhdGFfREhYMzYkbGZjCmRhdGFfREtPJGxmY19GQU5DSiA8LSBkYXRhX0ZBTkNKJGxmYwpnZ3NjYXR0ZXIoZGF0YV9ES08seCA9ImxmY19ESFgzNiIseT0ibGZjIixjb2xvcj0iaXNERSIsc2l6ZSA9IDAuOCwgYWxwaGE9MC41LCBwYWxldHRlID0gYygiZ3JheSIsbXlwYWxbM10pKSsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MC4xKSArIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTAuMSkgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKC01LDUpLCB4bGltPWMoLTUsNSkpCnBsb3RfTEZDX0RLT192c19ESFgzNiA8LSByYXN0ZXJpemUobGFzdF9wbG90KCksIGxheWVycz0nUG9pbnQnLCBkcGk9NjAwKQpgYGAKYGBge3IgZmlnLndpZHRoPTIsIGZpZy5oZWlnaHQ9Mn0KZ2dzY2F0dGVyKGRhdGFfREtPLHggPSJsZmNfRkFOQ0oiLHk9ImxmYyIsY29sb3I9ImlzREUiLHNpemUgPSAwLjgsIGFscGhhPTAuNSwgcGFsZXR0ZSA9IGMoImdyYXkiLG15cGFsWzNdKSkrIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTAuMSkgKyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0wLjEpICsgY29vcmRfY2FydGVzaWFuKHlsaW09YygtNSw1KSwgeGxpbT1jKC01LDUpKQpwbG90X0xGQ19ES09fdnNfRkFOQ0ogPC0gcmFzdGVyaXplKGxhc3RfcGxvdCgpLCBsYXllcnM9J1BvaW50JywgZHBpPTYwMCkKYGBgCmBgYHtyIGZpZy53aWR0aD0yLCBmaWcuaGVpZ2h0PTJ9CmRhdGFfREhYMzYkbGZjX0RLTyA8LSBkYXRhX0RLTyRsZmMKZ2dzY2F0dGVyKGRhdGFfREhYMzYseCA9ImxmYyIseT0ibGZjX0RLTyIsY29sb3I9ImlzREUiLHNpemUgPSAwLjgsIGFscGhhPTAuNSwgcGFsZXR0ZSA9IGMoImdyYXkiLG15cGFsWzFdKSkrIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTAuMSkgKyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0wLjEpICsgY29vcmRfY2FydGVzaWFuKHlsaW09YygtNSw1KSwgeGxpbT1jKC01LDUpKQpgYGAKCmBgYHtyfQpiZWQgPC0gYXMuZGF0YS5mcmFtZShjb3YuREhYMzYpWywxOjNdCgpyZXN1bHRzX3RhYmxlIDwtIGRhdGEuZnJhbWUoY2hyPWJlZCRzZXFuYW1lcyxzdGFydD1iZWQkc3RhcnQsZW5kPWJlZCRlbmQsbmFtZT1jb3YuV1QkbmFtZSwgYmFzZU1lYW49bGZjX0RLTyRiYXNlTWVhbixESFgzNj1kYXRhX0RIWDM2JGlzREUsRkFOQ0o9ZGF0YV9GQU5DSiRpc0RFLERLTz1kYXRhX0RLTyRpc0RFLERIWDM2bGZjPWRhdGFfREhYMzYkbGZjLEZBTkNKbGZjPWRhdGFfRkFOQ0okbGZjLERLT2xmYz1kYXRhX0RLTyRsZmMsZGlyPSIuIikKCnJlc3VsdHNfdGFibGUkbm9uc2lnIDwtICEocmVzdWx0c190YWJsZSRESFgzNiB8IHJlc3VsdHNfdGFibGUkRkFOQ0ogfCByZXN1bHRzX3RhYmxlJERLTykKCnJlc3VsdHNfdGFibGUkc2lnIDwtIGZhY3RvcigibG93bGZjIiwgbGV2ZWxzPWMoIm5vbnNpZyIsImxvd2xmYyIsIkZBTkNKIiwiREhYMzYiLCJES08iKSkKcmVzdWx0c190YWJsZSRzaWdbKHJlc3VsdHNfdGFibGUkbm9uc2lnKV0gPC0gIm5vbnNpZyIKcmVzdWx0c190YWJsZSRzaWdbKHJlc3VsdHNfdGFibGUkREtPICYgcmVzdWx0c190YWJsZSRES09sZmM+MSldIDwtICJES08iCnJlc3VsdHNfdGFibGUkc2lnWyhyZXN1bHRzX3RhYmxlJERIWDM2ICYgcmVzdWx0c190YWJsZSRESFgzNmxmYz4xKV0gPC0gIkRIWDM2IgpyZXN1bHRzX3RhYmxlJHNpZ1socmVzdWx0c190YWJsZSRGQU5DSiAmIHJlc3VsdHNfdGFibGUkRkFOQ0psZmM+MSldIDwtICJGQU5DSiIKCndyaXRlLnRhYmxlKHJlc3VsdHNfdGFibGUsIkc0X0NuVF9jb21iaW5lZF9wZWFrc19ERVNlcV9yZXN1bHRzLnR4dCIsIHJvdy5uYW1lcyA9IEYsIGNvbC5uYW1lcyA9IFQscXVvdGUgPSBGLCBzZXAgPSAiXHQiKQpgYGAKCmBgYHtyfQpyZXN1bHRzX3RhYmxlIDwtIHJlYWQudGFibGUoIkc0X0NuVF9jb21iaW5lZF9wZWFrc19ERVNlcV9yZXN1bHRzLnR4dCIsIGhlYWRlciA9IFQsIHNlcCA9ICJcdCIpCnJlc3VsdHNfdGFibGUkc2lnIDwtIGZhY3RvcihyZXN1bHRzX3RhYmxlJHNpZywgbGV2ZWxzPWMoIm5vbnNpZyIsImxvd2xmYyIsIkZBTkNKIiwiREhYMzYiLCJES08iKSkKCkRIWDM2X2JlZCA8LSByZXN1bHRzX3RhYmxlWyhyZXN1bHRzX3RhYmxlJERIWDM2ICYgcmVzdWx0c190YWJsZSRESFgzNmxmYz4xKSxjKDEsMiwzLDQsOSwxMildCndyaXRlLnRhYmxlKERIWDM2X2JlZCwiLi4vcGVha3MvRzRfQ25UX2NvbWJpbmVkX3BlYWtzX0RFU2VxX0RIWDM2X3NpZy5iZWQiLCByb3cubmFtZXMgPSBGLCBjb2wubmFtZXMgPSBGLHF1b3RlID0gRiwgc2VwID0gIlx0IikKCkZBTkNKX2JlZCA8LSByZXN1bHRzX3RhYmxlWyhyZXN1bHRzX3RhYmxlJEZBTkNKICYgcmVzdWx0c190YWJsZSRGQU5DSmxmYz4xKSxjKDEsMiwzLDQsMTAsMTIpXQp3cml0ZS50YWJsZShGQU5DSl9iZWQsIi4uL3BlYWtzL0c0X0NuVF9jb21iaW5lZF9wZWFrc19ERVNlcV9GQU5DSl9zaWcuYmVkIiwgcm93Lm5hbWVzID0gRiwgY29sLm5hbWVzID0gRixxdW90ZSA9IEYsIHNlcCA9ICJcdCIpCgpES09fYmVkIDwtIHJlc3VsdHNfdGFibGVbKHJlc3VsdHNfdGFibGUkREtPICYgcmVzdWx0c190YWJsZSRES09sZmM+MSksYygxLDIsMyw0LDExLDEyKV0Kd3JpdGUudGFibGUoREtPX2JlZCwiLi4vcGVha3MvRzRfQ25UX2NvbWJpbmVkX3BlYWtzX0RFU2VxX0RLT19zaWcuYmVkIiwgcm93Lm5hbWVzID0gRiwgY29sLm5hbWVzID0gRixxdW90ZSA9IEYsIHNlcCA9ICJcdCIpCgpub25zaWdfYmVkIDwtIHJlc3VsdHNfdGFibGVbcmVzdWx0c190YWJsZSRub25zaWcgLGMoMSwyLDMsNCwxMSwxMildCndyaXRlLnRhYmxlKG5vbnNpZ19iZWQsIi4uL3BlYWtzL0c0X0NuVF9jb21iaW5lZF9wZWFrc19ERVNlcV9ub25zaWcuYmVkIiwgcm93Lm5hbWVzID0gRiwgY29sLm5hbWVzID0gRixxdW90ZSA9IEYsIHNlcCA9ICJcdCIpCgpES09fYmVkX3RvcCA8LSByZXN1bHRzX3RhYmxlWyhyZXN1bHRzX3RhYmxlJERLTz09VFJVRSAmIHJlc3VsdHNfdGFibGUkREtPbGZjPjIgJiByZXN1bHRzX3RhYmxlJGJhc2VNZWFuID4gMTAwKSxjKDEsMiwzLDQsMTEsMTIpXQp3cml0ZS50YWJsZShES09fYmVkX3RvcCwiLi4vcGVha3MvRzRfQ25UX2NvbWJpbmVkX3BlYWtzX0RFU2VxX0RLT19zaWdfbGZjX2Jhc2VfY3V0b2ZmLmJlZCIsIHJvdy5uYW1lcyA9IEYsIGNvbC5uYW1lcyA9IEYscXVvdGUgPSBGLCBzZXAgPSAiXHQiKQoKCndyaXRlLnRhYmxlKGNiaW5kKHJlc3VsdHNfdGFibGVbLGMoMSwyLDMpXSxyZXN1bHRzX3RhYmxlJHNpZyxhcy5udW1lcmljKHJlc3VsdHNfdGFibGUkc2lnKSwiLiIpLCIuLi9wZWFrcy9HNF9DblRfY29tYmluZWRfcGVha3NfREVTZXFfc2lnX2NhdGVnb3JpZXMuYmVkIiwgcm93Lm5hbWVzID0gRiwgY29sLm5hbWVzID0gRixxdW90ZSA9IEYsIHNlcCA9ICJcdCIpCmBgYAoKYGBge3IgZmlnLndpZHRoPTIsIGZpZy5oZWlnaHQ9Mn0KbGlicmFyeShldWxlcnIpCnYgPC0gbGlzdChESFgzNj1ESFgzNl9iZWQkbmFtZSxGQU5DSj1GQU5DSl9iZWQkbmFtZSxES089REtPX2JlZCRuYW1lKQpwbG90X1Zlbm5fYWxsIDwtIHBsb3QoZXVsZXIodikscXVhbnRpdGllcz1ULCBib3JkZXI9ImJsYWNrIikKcGxvdF9WZW5uX2FsbApgYGAKYGBge3IgZmlnLndpZHRoPTIsIGZpZy5oZWlnaHQ9Mn0KbGlicmFyeShldWxlcnIpCkRLT25lZyA8LSByZXN1bHRzX3RhYmxlWyhyZXN1bHRzX3RhYmxlJERLTz09VFJVRSAmIHJlc3VsdHNfdGFibGUkREtPbGZjPCAtMSksYyg0KV0KdiA8LSBsaXN0KGFsbD1jb3YuV1QkbmFtZSxES09uZWc9REtPbmVnLERLTz1ES09fYmVkJG5hbWUpCnBsb3RfVmVubl9ES08gPC0gcGxvdChldWxlcih2KSxxdWFudGl0aWVzPVQpCnBsb3RfVmVubl9ES08KYGBgCmBgYHtyfQpkaXIuY3JlYXRlKCIuL3Bsb3RzIixzaG93V2FybmluZ3MgPSBGKQpnZ3NhdmUoInBsb3RzL3BlYWtzX0RFU2VxMl9NQV9ESFgzNi5wZGYiLHBsb3RfTUFfREhYMzYsd2lkdGggPSA0LCBoZWlnaHQ9IDQpCmdnc2F2ZSgicGxvdHMvcGVha3NfREVTZXEyX01BX0ZBTkNKLnBkZiIscGxvdF9NQV9GQU5DSix3aWR0aCA9IDQsIGhlaWdodD0gNCkKZ2dzYXZlKCJwbG90cy9wZWFrc19ERVNlcTJfTUFfREtPLnBkZiIscGxvdF9NQV9ES08sd2lkdGggPSA0LCBoZWlnaHQ9IDQpCmdnc2F2ZSgicGxvdHMvcGVha3NfREVTZXEyX0xGQ19ESFgzNi5wZGYiLHBsb3RfTEZDX0RLT192c19ESFgzNix3aWR0aCA9IDQsIGhlaWdodD0gNCkKZ2dzYXZlKCJwbG90cy9wZWFrc19ERVNlcTJfTEZDX0ZBTkNKLnBkZiIscGxvdF9MRkNfREtPX3ZzX0ZBTkNKLHdpZHRoID0gNCwgaGVpZ2h0PSA0KQpnZ3NhdmUoInBsb3RzL3BlYWtzX0RFU2VxMl9WZW5uX0tPcy5wZGYiLHBsb3RfVmVubl9hbGwsd2lkdGggPSA0LCBoZWlnaHQ9IDQpCmdnc2F2ZSgicGxvdHMvcGVha3NfREVTZXEyX1Zlbm5fREtPX3ZzX2FsbC5wZGYiLHBsb3RfVmVubl9ES08sd2lkdGggPSA0LCBoZWlnaHQ9IDQpCmBgYCAKCmBgYHtyIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTR9CmxpYnJhcnkoY293cGxvdCkKZGlyLmNyZWF0ZSgiLi9wYW5lbHMiLHNob3dXYXJuaW5ncyA9IEYpCgpsaWJyYXJ5KCJjb3dwbG90IikKcCA8LSBnZ2RyYXcoKSArCiAgZHJhd19wbG90KHBsb3RfTUFfREhYMzYsIHggPSAwLCB5ID0gMC41LCB3aWR0aCA9IC4zMywgaGVpZ2h0ID0gLjUpICsKICBkcmF3X3Bsb3QocGxvdF9NQV9GQU5DSiwgeCA9IC4zMywgeSA9IDAuNSwgd2lkdGggPSAuMzMsIGhlaWdodCA9IC41KSArCiAgZHJhd19wbG90KHBsb3RfTUFfREtPLCB4ID0gMC42NiwgeSA9IDAuNSwgd2lkdGggPSAuMzMsIGhlaWdodCA9IDAuNSkgKwogIGRyYXdfcGxvdChwbG90X0xGQ19ES09fdnNfREhYMzYsIHggPSAwLCB5ID0gMCwgd2lkdGggPSAwLjMzLCBoZWlnaHQgPSAwLjUpICsKICBkcmF3X3Bsb3QocGxvdF9MRkNfREtPX3ZzX0ZBTkNKLCB4ID0gMC4zMywgeSA9IDAsIHdpZHRoID0gMC4zMywgaGVpZ2h0ID0gMC41KSArCiAgZHJhd19wbG90KHBsb3RfVmVubl9hbGwsIHggPSAwLjY2LCB5ID0gMCwgd2lkdGggPSAwLjMzLCBoZWlnaHQgPSAwLjUpICsKICBkcmF3X3Bsb3RfbGFiZWwobGFiZWwgPSBjKCJhIiwgImIiLCAiYyIsImQiLCJlIiwiZiIpLCBzaXplID0gMTUsCiAgICAgICAgICAgICAgICAgIHggPSBjKDAsIDAuMzMsIDAuNjYsIDAsIDAuMzMsIDAuNjYpLCB5ID0gYygxLCAxLCAxLCAwLjUsIDAuNSwgMC41KSkKcApnZ3NhdmUoInBhbmVscy9wZWFrc19ERVNlcTIucGRmIixwKQpgYGAgCmBgYHtyIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTR9CmxpYnJhcnkoY293cGxvdCkKZGlyLmNyZWF0ZSgiLi9wYW5lbHMiLHNob3dXYXJuaW5ncyA9IEYpCgpsaWJyYXJ5KCJjb3dwbG90IikKcCA8LSBnZ2RyYXcoKSArCiAgZHJhd19wbG90KHBsb3RfTUFfREhYMzYsIHggPSAwLCB5ID0gMC41LCB3aWR0aCA9IC4zMywgaGVpZ2h0ID0gLjUpICsKICBkcmF3X3Bsb3QocGxvdF9NQV9GQU5DSiwgeCA9IC4zMywgeSA9IDAuNSwgd2lkdGggPSAuMzMsIGhlaWdodCA9IC41KSArCiAgZHJhd19wbG90KHBsb3RfTUFfREtPLCB4ID0gMC42NiwgeSA9IDAuNSwgd2lkdGggPSAuMzMsIGhlaWdodCA9IDAuNSkgKwogIGRyYXdfcGxvdChwbG90X1hZX0RIWDM2LCB4ID0gMCwgeSA9IDAsIHdpZHRoID0gMC4zMywgaGVpZ2h0ID0gMC41KSArCiAgZHJhd19wbG90KHBsb3RfWFlfRkFOQ0osIHggPSAwLjMzLCB5ID0gMCwgd2lkdGggPSAwLjMzLCBoZWlnaHQgPSAwLjUpICsKICBkcmF3X3Bsb3QocGxvdF9YWV9ES08sIHggPSAwLjY2LCB5ID0gMCwgd2lkdGggPSAwLjMzLCBoZWlnaHQgPSAwLjUpICsKICBkcmF3X3Bsb3RfbGFiZWwobGFiZWwgPSBjKCJhIiwgImIiLCAiYyIsImQiLCJlIiwiZiIpLCBzaXplID0gMTUsCiAgICAgICAgICAgICAgICAgIHggPSBjKDAsIDAuMzMsIDAuNjYsIDAsIDAuMzMsIDAuNjYpLCB5ID0gYygxLCAxLCAxLCAwLjUsIDAuNSwgMC41KSkKcApnZ3NhdmUoInBhbmVscy9wZWFrc19ERVNlcTJfc2NhdHRlci5wZGYiLHApCmBgYCAKCmBgYHtyfQpjb3YgPC0gY2JpbmQoIGFzLmRhdGEuZnJhbWUoY292LldUKVssMTo4XSwgCiAgICAgICAgICAgICAgYXMuZGF0YS5mcmFtZShjb3YuREhYMzYpWyw2OjhdLCAKICAgICAgICAgICAgICBhcy5kYXRhLmZyYW1lKGNvdi5GQU5DSilbLDY6OF0sIAogICAgICAgICAgICAgIGFzLmRhdGEuZnJhbWUoY292LkRLTylbLDY6OF0pCgpjb2xuYW1lcyhjb3YpIDwtIGMoY29sbmFtZXMoY292KVsxOjVdLCJXVDEiLCJXVDIiLCJXVDMiLCJESFgxIiwiREhYMiIsIkRIWDMiLCJGQU4xIiwiRkFOMiIsIkZBTjMiLCJES08xIiwiREtPMiIsIkRLTzMiKQoKcm93bmFtZXMoY292KSA8LSBhcy5kYXRhLmZyYW1lKGNvdi5XVCkkbmFtZQoKY292JERIWDM2X3NpZyA8LSByb3duYW1lcyhjb3YpICVpbiUgREhYMzZfYmVkJG5hbWUKY292JEZBTkNKX3NpZyA8LSByb3duYW1lcyhjb3YpICVpbiUgRkFOQ0pfYmVkJG5hbWUKY292JERLT19zaWcgPC0gcm93bmFtZXMoY292KSAlaW4lIERLT19iZWQkbmFtZQpjb3Ykbm9uX3NpZyA8LSB3aXRoKGNvdiwgIShESFgzNl9zaWcgfCBGQU5DSl9zaWcgfCBES09fc2lnKSkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD0zfQpsaWJyYXJ5KHJlc2hhcGUyKQptZGYgPC0gbWVsdChkYXRhLmZyYW1lKG5hbWU9cm93bmFtZXMoY292KSxjb3ZbLDY6MjFdKSkKbWRmIDwtIG1kZlttZGYkdmFsdWU8NTAwLF0KbWRmJGNvbmQgPC0gIldUIgptZGYkY29uZFtncmVwKCJESFgiLG1kZiR2YXJpYWJsZSldIDwtICJESFgzNi0vLSIKbWRmJGNvbmRbZ3JlcCgiRkFOIixtZGYkdmFyaWFibGUpXSA8LSAiRkFOQ0otLy0iCm1kZiRjb25kW2dyZXAoIkRLTyIsbWRmJHZhcmlhYmxlKV0gPC0gIkRIWDM2LS8tRkFOQ0otLy0iCnBsb3RfdmlvbF9yZXBfYWxsX3BlYWtzIDwtIGdndmlvbGluKG1kZiwgeD0idmFyaWFibGUiLHk9InZhbHVlIixmaWxsPSJjb25kIixwYWxldHRlID0gbXlwYWwsIGFkZD0ibWVhbl9zZCIpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsNTApKQpwbG90X3Zpb2xfcmVwX2FsbF9wZWFrcwpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9MiwgZmlnLndpZHRoPTN9CnBsb3RfdmlvbF9yZXBfREhYMzZfcGVha3MgPC0gZ2d2aW9saW4obWRmW21kZiRESFgzNl9zaWcsXSwgeD0idmFyaWFibGUiLHk9InZhbHVlIixmaWxsPSJjb25kIixwYWxldHRlID0gbXlwYWwsIGFkZD0ibWVhbl9zZCIpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsNTApKQpwbG90X3Zpb2xfcmVwX0RIWDM2X3BlYWtzCmBgYAoKYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9M30KZ2d2aW9saW4obWRmW21kZiRGQU5DSl9zaWcsXSwgeD0idmFyaWFibGUiLHk9InZhbHVlIixmaWxsPSJjb25kIixwYWxldHRlID0gbXlwYWwsIGFkZD0ibWVhbl9zZCIpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsNTApKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9MiwgZmlnLndpZHRoPTN9CnBsb3RfdmlvbF9yZXBfREtPX3BlYWtzIDwtIGdndmlvbGluKG1kZlttZGYkREtPX3NpZyxdLCB4PSJ2YXJpYWJsZSIseT0idmFsdWUiLGZpbGw9ImNvbmQiLHBhbGV0dGUgPSBteXBhbCwgYWRkPSJtZWFuX3NkIikgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCw1MCkpCnBsb3RfdmlvbF9yZXBfREtPX3BlYWtzCmBgYApgYGB7ciBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD0zfQpwbG90X3Zpb2xfcmVwX25vbnNpZ19wZWFrcyA8LSBnZ3Zpb2xpbihtZGZbbWRmJG5vbl9zaWcsXSwgeD0idmFyaWFibGUiLHk9InZhbHVlIixmaWxsPSJjb25kIixwYWxldHRlID0gbXlwYWwsIGFkZD0ibWVhbl9zZCIpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsNTApKQpwbG90X3Zpb2xfcmVwX25vbnNpZ19wZWFrcwpgYGAKCmBgYHtyfQpnZ3NhdmUoInBsb3RzL3BlYWtzX0RFU2VxMl92aW9sX3JlcF9hbGwucGRmIixwbG90X3Zpb2xfcmVwX2FsbF9wZWFrcykKZ2dzYXZlKCJwbG90cy9wZWFrc19ERVNlcTJfdmlvbF9yZXBfREtPLnBkZiIscGxvdF92aW9sX3JlcF9ES09fcGVha3MpCmdnc2F2ZSgicGxvdHMvcGVha3NfREVTZXEyX3Zpb2xfcmVwX0RIWDM2LnBkZiIscGxvdF92aW9sX3JlcF9ESFgzNl9wZWFrcykKZ2dzYXZlKCJwbG90cy9wZWFrc19ERVNlcTJfdmlvbF9yZXBfbm9uc2lnLnBkZiIscGxvdF92aW9sX3JlcF9ub25zaWdfcGVha3MpCmBgYCAKCmBgYHtyIGZpZy5oZWlnaHQ9MiwgZmlnLndpZHRoPTN9CnNkZiA8LSBhZ2dyZWdhdGUodmFsdWUgfiBuYW1lICsgY29uZCwgZGF0YT1tZGYsIEZVTj0ibWVhbiIpCnNkZiRjb25kIDwtIGZhY3RvcihzZGYkY29uZCxsZXZlbHM9YygiV1QiLCJESFgzNi0vLSIsIkZBTkNKLS8tIiwiREhYMzYtLy1GQU5DSi0vLSIpKQpnZ3Zpb2xpbihzZGYsIHg9ImNvbmQiLHk9InZhbHVlIixmaWxsPSJjb25kIixwYWxldHRlID0gbXlwYWxbYyg0LDEsMiwzKV0sIGFkZD0ibWVhbl9zZCIpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsNTApKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9MiwgZmlnLndpZHRoPTN9CnNkZiRESFgzNl9zaWcgPC0gc2RmJG5hbWUgJWluJSBESFgzNl9iZWQkbmFtZQpzZGYkRkFOQ0pfc2lnIDwtIHNkZiRuYW1lICVpbiUgRkFOQ0pfYmVkJG5hbWUKc2RmJERLT19zaWcgPC0gc2RmJG5hbWUgJWluJSBES09fYmVkJG5hbWUKc2RmJERLT190b3AgPC0gc2RmJG5hbWUgJWluJSBES09fYmVkX3RvcCRuYW1lCmdndmlvbGluKHNkZltzZGYkREhYMzYsXSwgeD0iY29uZCIseT0idmFsdWUiLGZpbGw9ImNvbmQiLHBhbGV0dGUgPSBteXBhbFtjKDQsMSwyLDMpXSwgYWRkPSJtZWFuX3NkIikgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCw3NSkpCmBgYAoKYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9M30KZ2d2aW9saW4oc2RmW3NkZiRGQU5DSl9zaWcsXSwgeD0iY29uZCIseT0idmFsdWUiLGZpbGw9ImNvbmQiLHBhbGV0dGUgPSBteXBhbFtjKDQsMSwyLDMpXSwgYWRkPSJtZWFuX3NkIikgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCw3NSkpCmBgYAoKYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9M30KcGxvdF92aW9sX0RLT19wZWFrcyA8LSBnZ3Zpb2xpbihzZGZbc2RmJERLT19zaWcsXSwgeD0iY29uZCIseT0idmFsdWUiLGZpbGw9ImNvbmQiLHBhbGV0dGUgPSBteXBhbFtjKDQsMSwyLDMpXSwgYWRkPSJtZWFuX3NkIikgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCw3NSkpCnBsb3RfdmlvbF9ES09fcGVha3MKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD0zfQpnZ3Zpb2xpbihzZGZbc2RmJERLT190b3AsXSwgeD0iY29uZCIseT0idmFsdWUiLGZpbGw9ImNvbmQiLHBhbGV0dGUgPSBteXBhbFtjKDQsMSwyLDMpXSwgYWRkPSJtZWFuX3NkIikgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCw3NSkpCmBgYAoKIyMjIGFubm90YXRlIHBlYWsgdGFibGUKYGBge3J9CmxpYnJhcnkoYmVkc2NvdXQpCgpwZWFrX3VuaXZlcnNlIDwtICIuLi9wZWFrcy9HNF9jb21iaW5lZF9taW4zcmVwLmJlZCIKCmJlZF9wZWFrcyA8LSBydHJhY2tsYXllcjo6aW1wb3J0KHBlYWtfdW5pdmVyc2UpCmNocm9taG1tX2dyIDwtIHJ0cmFja2xheWVyOjppbXBvcnQoY2hyb21obW0pCgoKYmVkX3BlYWtzX2Fubm90YXRlZCA8LSB1bmlxdWUoaW1wdXRlX2ZlYXR1cmUoYmVkX3BlYWtzLCBjaHJvbWhtbV9nciwgIm5hbWUiKSkKYmVkX3BlYWtzX2Fubm90YXRlZF9kZiA8LSBhcy5kYXRhLmZyYW1lKGJlZF9wZWFrc19hbm5vdGF0ZWQpCiMgSWYgeW91IHdhbnQgdG8gZXhwb3J0IHRvIEJFRCBmaWxlIHdpdGggcnRyYWNrbGF5ZXIgdGhlbiB5b3UKIyBkbyBuZWVkIHRvIGV4cGxpY2l0bHkgb3ZlcndyaXRlIHRoZSBuYW1lOgpiZWRfcGVha3NfYW5ub3RhdGVkJG5hbWUgPC0gYmVkX3BlYWtzX2Fubm90YXRlZCRmZWF0dXJlCnJ0cmFja2xheWVyOjpleHBvcnQodW5pcXVlKGJlZF9wZWFrc19hbm5vdGF0ZWQpLCAiLi4vcGVha3MvRzRfQ25UX2NvbWJpbmVkX3BlYWtzX0RFU2VxX2Fubm90YXRlZF92Mi5iZWQiKQoKY2hyb21obW0xN19nciA8LSBydHJhY2tsYXllcjo6aW1wb3J0KCIuLi9nZW5vbWUvQ2hyb21ITU0xNy5jaHI5Lm1tMzlsaWZ0LmJlZCIpCmJlZF9wZWFrc19obW0xNyA8LSB1bmlxdWUoaW1wdXRlX2ZlYXR1cmUoYmVkX3BlYWtzLCBjaHJvbWhtbTE3X2dyLCAibmFtZSIpKQojIElmIHlvdSB3YW50IHRvIGV4cG9ydCB0byBCRUQgZmlsZSB3aXRoIHJ0cmFja2xheWVyIHRoZW4geW91CiMgZG8gbmVlZCB0byBleHBsaWNpdGx5IG92ZXJ3cml0ZSB0aGUgbmFtZToKYmVkX3BlYWtzX2htbTE3JG5hbWUgPC0gYmVkX3BlYWtzX2htbTE3JGZlYXR1cmUKYmVkX3BlYWtzX2htbTE3JHNjb3JlW2lzLm5hKGJlZF9wZWFrc19obW0xNyRzY29yZSldIDwtIDAKcnRyYWNrbGF5ZXI6OmV4cG9ydChiZWRfcGVha3NfaG1tMTcsICIuLi9wZWFrcy9HNF9DblRfY29tYmluZWRfcGVha3NfREVTZXFfYW5ub3RhdGVkX0Nocm9tSE1NMTcuYmVkIikKCnJtc2tfZ3IgPC0gcnRyYWNrbGF5ZXI6OmltcG9ydCgiLi4vZ2Vub21lL3Jtc2subHQyMDBicC5tbTM5LmJlZCIpCmJlZF9wZWFrc19ybXNrIDwtIGltcHV0ZV9mZWF0dXJlKGJlZF9wZWFrcywgcm1za19nciwgIm5hbWUiKQojIElmIHlvdSB3YW50IHRvIGV4cG9ydCB0byBCRUQgZmlsZSB3aXRoIHJ0cmFja2xheWVyIHRoZW4geW91CiMgZG8gbmVlZCB0byBleHBsaWNpdGx5IG92ZXJ3cml0ZSB0aGUgbmFtZToKYmVkX3BlYWtzX3Jtc2skbmFtZSA8LSBiZWRfcGVha3Nfcm1zayRmZWF0dXJlCmJlZF9wZWFrc19ybXNrJHNjb3JlW2lzLm5hKGJlZF9wZWFrc19ybXNrJHNjb3JlKV0gPC0gMApydHJhY2tsYXllcjo6ZXhwb3J0KGJlZF9wZWFrc19ybXNrLCAiLi4vcGVha3MvRzRfQ25UX2NvbWJpbmVkX3BlYWtzX0RFU2VxX2Fubm90YXRlZF9ybXNrLmJlZCIpCgpiZWRfcGVha3NfdGFibGUgPC0gY2JpbmQoYmVkX3BlYWtzX2Fubm90YXRlZF9kZixkYXRhLmZyYW1lKGJhc2VNZWFuPWxmY19ES08kYmFzZU1lYW4sbm9uc2lnPSghZGF0YV9ESFgzNiRpc0RFICYgIWRhdGFfRkFOQ0okaXNERSAmICFkYXRhX0RLTyRpc0RFKSwgREhYMzY9KGRhdGFfREhYMzYkaXNERSAmIGRhdGFfREhYMzYkbGZjPjEpLEZBTkNKPShkYXRhX0ZBTkNKJGlzREUgJiBkYXRhX0ZBTkNKJGxmYz4xKSxES089KGRhdGFfREtPJGlzREUmZGF0YV9ES08kbGZjPjEpLERIWDM2bGZjPWRhdGFfREhYMzYkbGZjLEZBTkNKbGZjPWRhdGFfRkFOQ0okbGZjLERLT2xmYz1kYXRhX0RLTyRsZmMpKQoKd3JpdGUudGFibGUoYmVkX3BlYWtzX3RhYmxlLCJHNF9DblRfY29tYmluZWRfcGVha3NfREVTZXFfYW5ub3RhdGVkX3YyLnR4dCIsIHJvdy5uYW1lcyA9IEYsIGNvbC5uYW1lcyA9IFQscXVvdGUgPSBGLCBzZXAgPSAiXHQiKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9MiwgZmlnLndpZHRoPTJ9CiNyZWFkIGluIC0gaWYgeW91IHdhbnQgdG8gc2tpcCBkZSBub3ZvIGdlbmVyYXRpb24KYmVkX3BlYWtzX3RhYmxlIDwtIHJlYWQudGFibGUoIkc0X0NuVF9jb21iaW5lZF9wZWFrc19ERVNlcV9hbm5vdGF0ZWRfdjIudHh0IiwgaGVhZGVyID0gVCwgc2VwID0gIlx0IikKCnZwYWw9Y29sb3JSYW1wUGFsZXR0ZShjKCJjb3JuZmxvd2VyYmx1ZSIsIm9yYW5nZSIsInJlZDIiKSkKc3RhdHMgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShiZWRfcGVha3NfdGFibGUkZmVhdHVyZSkpCnBsb3RfZG9udXRfYWxsIDwtIGdnZG9udXRjaGFydChzdGF0cyx4ID0gIkZyZXEiLGxhYmVsPSJWYXIxIixmaWxsPXZwYWwoMTApKQpwbG90X2RvbnV0X2FsbApgYGAKCiMjIyBESiBQZWFrIEFubm90YXRpb24KYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9Mn0KYmVkX0RKIDwtIGJlZF9wZWFrc190YWJsZVtiZWRfcGVha3NfdGFibGUkREtPLGMoMSwyLDMsNiwxNiw1KV0KYmVkX0RKJG5hbWUgPC0gIkRKIgp3cml0ZS50YWJsZShiZWRfREosIi4uL3BlYWtzL0c0X0NuVF9jb21iaW5lZF9wZWFrc19ESi5iZWQiLCByb3cubmFtZXMgPSBGLCBjb2wubmFtZXMgPSBGLHF1b3RlID0gRiwgc2VwID0gIlx0IikKCnN0YXRzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoYmVkX3BlYWtzX3RhYmxlJGZlYXR1cmVbYmVkX3BlYWtzX3RhYmxlJERLT10pKQpwbG90X2RvbnV0X0RKIDwtIGdnZG9udXRjaGFydChzdGF0cyx4ID0gIkZyZXEiLGxhYmVsPSJWYXIxIixmaWxsPXZwYWwoMTApKQpwbG90X2RvbnV0X0RKCmBgYAoKIyMjIG5vbi1ESiBQZWFrIEFubm90YXRpb24KYGBge3IgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9Mn0KYmVkX25vbkRKIDwtIGJlZF9wZWFrc190YWJsZVtiZWRfcGVha3NfdGFibGUkbm9uc2lnLGMoMSwyLDMsNiwxNiw1KV0KYmVkX25vbkRKJG5hbWUgPC0gIm5vbkRKIgp3cml0ZS50YWJsZShiZWRfbm9uREosIi4uL3BlYWtzL0c0X0NuVF9jb21iaW5lZF9wZWFrc19ub25ESi5iZWQiLCByb3cubmFtZXMgPSBGLCBjb2wubmFtZXMgPSBGLHF1b3RlID0gRiwgc2VwID0gIlx0IikKCmJlZF9ESiRES09sZmMgPC0gMQpiZWRfbm9uREokREtPbGZjIDwtIDAKCndyaXRlLnRhYmxlKHJiaW5kKGJlZF9ESixiZWRfbm9uREopLCIuLi9wZWFrcy9HNF9DblRfY29tYmluZWRfcGVha3NfREpfbm9uREouYmVkIiwgcm93Lm5hbWVzID0gRiwgY29sLm5hbWVzID0gRixxdW90ZSA9IEYsIHNlcCA9ICJcdCIpCgpzdGF0cyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKGJlZF9wZWFrc190YWJsZSRmZWF0dXJlW2JlZF9wZWFrc190YWJsZSRub25zaWddKSkKcGxvdF9kb251dF9ub25ESiA8LSBnZ2RvbnV0Y2hhcnQoc3RhdHMseCA9ICJGcmVxIixsYWJlbD0iVmFyMSIsZmlsbD12cGFsKDEwKSkKcGxvdF9kb251dF9ub25ESgpgYGAKYGBge3J9Cmdnc2F2ZSgicGxvdHMvcGxvdF9kb251dF9ESi5wZGYiLHBsb3RfZG9udXRfREopCmdnc2F2ZSgicGxvdHMvcGxvdF9kb251dF9ub25ESi5wZGYiLHBsb3RfZG9udXRfbm9uREopCmdnc2F2ZSgicGxvdHMvcGxvdF9kb251dF9hbGwucGRmIixwbG90X2RvbnV0X2FsbCkKYGBgIAoKCmBgYHtyIGZpZy5oZWlnaHQ9MywgZmlnLndpZHRoPTR9CnZwYWw9Y29sb3JSYW1wUGFsZXR0ZShjKCJsaWdodGdyZWVuIiwiY29ybmZsb3dlcmJsdWUiLCJvcmFuZ2UiLCJyZWQyIikpCgpzdGF0cyA8LSBkYXRhLmZyYW1lKGFzLmRhdGEuZnJhbWUodGFibGUoYmVkX3BlYWtzX3RhYmxlJGZlYXR1cmUpKVsxXSxhcy5kYXRhLmZyYW1lKHRhYmxlKGJlZF9wZWFrc190YWJsZSRmZWF0dXJlW2JlZF9wZWFrc190YWJsZSRES09dKSlbMl0sYXMuZGF0YS5mcmFtZSh0YWJsZShiZWRfcGVha3NfdGFibGUkZmVhdHVyZVtiZWRfcGVha3NfdGFibGUkbm9uc2lnXSkpWzJdKQoKY29sbmFtZXMoc3RhdHMpIDwtIGMoIlN0YXRlIiwiREoiLCJub25ESiIpCgojc3RhdHMkREhYMzY9c3RhdHMkREovc3VtKHN0YXRzJERKKSoxMDAKI3N0YXRzJEZBTkNKPXN0YXRzJG5vbkRKL3N1bShzdGF0cyRub25ESikqMTAwCgptZGYgPC0gbWVsdChzdGF0cykKbWRmJFN0YXRlIDwtIGZhY3RvcihtZGYkU3RhdGUsbGV2ZWxzPWxldmVscyhtZGYkU3RhdGUpW2MoMSwzLDUsNyw0LDYsMTAsOCw5LDIpXSkKY29scz1jKHZwYWwoMTEpW2MoNCw1LDMsMiw5LDgsNyldLCIjREREREREIiwiI0VFRUVFRSIsdnBhbCgxMSlbMTBdKQpwbG90X2Jhcl9jaHJvbWhtbV9hbm5vIDwtIGdnYmFycGxvdChtZGYseCA9ICJ2YXJpYWJsZSIseT0idmFsdWUiLGZpbGw9IlN0YXRlIixwYWxldHRlID1jb2xzLCAgb3JpZW50YXRpb24gPSBjKCJob3Jpem9udGFsIikpIApwbG90X2Jhcl9jaHJvbWhtbV9hbm5vCmBgYAoKYGBge3IgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9NH0KdnBhbD1jb2xvclJhbXBQYWxldHRlKGMoImxpZ2h0Z3JlZW4iLCJjb3JuZmxvd2VyYmx1ZSIsIm9yYW5nZSIsInJlZDIiKSkKCnN0YXRzIDwtIGRhdGEuZnJhbWUoYXMuZGF0YS5mcmFtZSh0YWJsZShiZWRfcGVha3NfdGFibGUkZmVhdHVyZSkpWzFdLGFzLmRhdGEuZnJhbWUodGFibGUoYmVkX3BlYWtzX3RhYmxlJGZlYXR1cmUpKVsyXSxhcy5kYXRhLmZyYW1lKHRhYmxlKGJlZF9wZWFrc190YWJsZSRmZWF0dXJlW2JlZF9wZWFrc190YWJsZSRES09dKSlbMl0sYXMuZGF0YS5mcmFtZSh0YWJsZShiZWRfcGVha3NfdGFibGUkZmVhdHVyZVtiZWRfcGVha3NfdGFibGUkbm9uc2lnXSkpWzJdKQoKY29sbmFtZXMoc3RhdHMpIDwtIGMoIlN0YXRlIiwiYWxsIiwiREoiLCJub25ESiIpCgojc3RhdHMkREhYMzY9c3RhdHMkREovc3VtKHN0YXRzJERKKSoxMDAKI3N0YXRzJEZBTkNKPXN0YXRzJG5vbkRKL3N1bShzdGF0cyRub25ESikqMTAwCgptZGYgPC0gbWVsdChzdGF0cykKbWRmJFN0YXRlIDwtIGZhY3RvcihtZGYkU3RhdGUsbGV2ZWxzPWxldmVscyhtZGYkU3RhdGUpW2MoMSwzLDUsNyw0LDYsMTAsOCw5LDIpXSkKY29scz1jKHZwYWwoMTEpW2MoNCw1LDMsMiw5LDgsNyldLCIjREREREREIiwiI0VFRUVFRSIsdnBhbCgxMSlbMTBdKQpwbG90X2Jhcl9jaHJvbWhtbV9hbm5vX2FsbCA8LSBnZ2JhcnBsb3QobWRmLHggPSAidmFyaWFibGUiLHk9InZhbHVlIixmaWxsPSJTdGF0ZSIscGFsZXR0ZSA9Y29scywgIG9yaWVudGF0aW9uID0gYygiaG9yaXpvbnRhbCIpKSAKcGxvdF9iYXJfY2hyb21obW1fYW5ub19hbGwKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD00fQpzdGF0cyRESj1zdGF0cyRESi9zdW0oc3RhdHMkREopKjEwMApzdGF0cyRub25ESj1zdGF0cyRub25ESi9zdW0oc3RhdHMkbm9uREopKjEwMApzdGF0cyRhbGw9c3RhdHMkYWxsL3N1bShzdGF0cyRhbGwpKjEwMAptZGYgPC0gbWVsdChzdGF0cykKbWRmJFN0YXRlIDwtIGZhY3RvcihtZGYkU3RhdGUsbGV2ZWxzPWxldmVscyhtZGYkU3RhdGUpW2MoMSwzLDUsNyw0LDYsMTAsOCw5LDIpXSkKY29scz1jKHZwYWwoMTEpW2MoNCw1LDMsMiw5LDgsNyldLCIjREREREREIiwiI0VFRUVFRSIsdnBhbCgxMSlbMTBdKQpwbG90X2Jhcl9jaHJvbWhtbV9hbm5vX25vcm0gPC0gZ2diYXJwbG90KG1kZix4ID0gInZhcmlhYmxlIix5PSJ2YWx1ZSIsZmlsbD0iU3RhdGUiLHBhbGV0dGUgPWNvbHMsICBvcmllbnRhdGlvbiA9IGMoImhvcml6b250YWwiKSkgCnBsb3RfYmFyX2Nocm9taG1tX2Fubm9fbm9ybQpgYGAKYGBge3J9Cmdnc2F2ZSgicGxvdHMvcGxvdF9iYXJfY2hyb21obW0ucGRmIixwbG90X2Jhcl9jaHJvbWhtbV9hbm5vKQpnZ3NhdmUoInBsb3RzL3Bsb3RfYmFyX2Nocm9taG1tX3JlbC5wZGYiLHBsb3RfYmFyX2Nocm9taG1tX2Fubm9fbm9ybSkKYGBgIAoKYGBge3IgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9M30KdnBhbD1jb2xvclJhbXBQYWxldHRlKGMoImxpZ2h0Z3JlZW4iLCJjb3JuZmxvd2VyYmx1ZSIsIm9yYW5nZSIsInJlZDIiKSkKCnN0YXRzIDwtIGRhdGEuZnJhbWUoYXMuZGF0YS5mcmFtZSh0YWJsZShiZWRfcGVha3NfdGFibGUkZmVhdHVyZSkpLERIWDM2PWFzLmRhdGEuZnJhbWUodGFibGUoYmVkX3BlYWtzX3RhYmxlJGZlYXR1cmVbYmVkX3BlYWtzX3RhYmxlJERIWDM2PT1UUlVFXSkpWzJdLEZBTkNKPWFzLmRhdGEuZnJhbWUodGFibGUoYmVkX3BlYWtzX3RhYmxlJGZlYXR1cmVbYmVkX3BlYWtzX3RhYmxlJEZBTkNKPT1UUlVFXSkpWzJdLERLTz1hcy5kYXRhLmZyYW1lKHRhYmxlKGJlZF9wZWFrc190YWJsZSRmZWF0dXJlW2JlZF9wZWFrc190YWJsZSRES089PVRSVUVdKSlbMl0pCmNvbG5hbWVzKHN0YXRzKSA8LSBjKCJTdGF0ZSIsIlRvdGFsIiwiREhYMzYiLCJGQU5DSiIsIkRLTyIpCgpzdGF0cyRUb3RhbD1zdGF0cyRUb3RhbC9zdW0oc3RhdHMkVG90YWwpKjEwMApzdGF0cyRESFgzNj1zdGF0cyRESFgzNi9zdW0oc3RhdHMkREhYMzYpKjEwMApzdGF0cyRGQU5DSj1zdGF0cyRGQU5DSi9zdW0oc3RhdHMkRkFOQ0opKjEwMApzdGF0cyRES089c3RhdHMkREtPL3N1bShzdGF0cyRES08pKjEwMAptZGYgPC0gbWVsdChzdGF0cykKbWRmJFN0YXRlIDwtIGZhY3RvcihtZGYkU3RhdGUsbGV2ZWxzPWxldmVscyhtZGYkU3RhdGUpW2MoMSwzLDUsNyw0LDYsMTAsOCw5LDIpXSkKY29scz1jKHZwYWwoMTEpW2MoNCw1LDMsMiw5LDgsNyldLCIjREREREREIiwiI0VFRUVFRSIsdnBhbCgxMSlbMTBdKQpwbG90X2Jhcl9jaHJvbWhtbV9hbm5vIDwtIGdnYmFycGxvdChtZGYseCA9ICJ2YXJpYWJsZSIseT0idmFsdWUiLGZpbGw9IlN0YXRlIixwYWxldHRlID1jb2xzLGxhYmVsPW1kZiRTdGF0ZSkKcGxvdF9iYXJfY2hyb21obW1fYW5ubwpgYGAKCgoKYGBge3IgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9M30KcCA8LSBnZ2RyYXcoKSArCiAgZHJhd19wbG90KHBsb3RfYmFyX2Nocm9taG1tX2Fubm8sIHggPSAwLCB5ID0gMCwgd2lkdGggPSAuMjAsIGhlaWdodCA9IDEpICsKICBkcmF3X3Bsb3QocGxvdF92aW9sX3JlcF9ES09fcGVha3MsIHggPSAuMiwgeSA9IDAsIHdpZHRoID0gLjQwLCBoZWlnaHQgPSAwLjcpICsKICBkcmF3X3Bsb3QocGxvdF92aW9sX3JlcF9ub25zaWdfcGVha3MsIHggPSAwLjYsIHkgPSAwLCB3aWR0aCA9IC40MCwgaGVpZ2h0ID0gMC43KSArCiAgZHJhd19wbG90X2xhYmVsKGxhYmVsID0gYygiYSIsICJiIiwgImMiKSwgc2l6ZSA9IDE1LAogICAgICAgICAgICAgICAgICB4ID0gYygwLCAwLjIsIDAuNiksIHkgPSBjKDEsIDAuOCwgMC44KSkKcApnZ3NhdmUoInBhbmVscy9wZWFrX2Fubm9fdmlvbGluX3YxLnBkZiIscCkKYGBgIApgYGB7ciBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD0zfQoKcCA8LSBnZ2RyYXcoKSArCiAgZHJhd19wbG90KHBsb3RfYmFyX2Nocm9taG1tX2Fubm8sIHggPSAwLCB5ID0gMCwgd2lkdGggPSAuNCwgaGVpZ2h0ID0gMSkgKwogIGRyYXdfcGxvdChwbG90X3Zpb2xfcmVwX0RLT19wZWFrcywgeCA9IC40LCB5ID0gMC41LCB3aWR0aCA9IC42MCwgaGVpZ2h0ID0gMC41KSArCiAgZHJhd19wbG90KHBsb3RfdmlvbF9yZXBfbm9uc2lnX3BlYWtzLCB4ID0gMC40LCB5ID0gMCwgd2lkdGggPSAuNjAsIGhlaWdodCA9IDAuNSkgKwogIGRyYXdfcGxvdF9sYWJlbChsYWJlbCA9IGMoImEiLCAiYiIsICJjIiksIHNpemUgPSAxNSwKICAgICAgICAgICAgICAgICAgeCA9IGMoMCwgMC40LCAwLjQpLCB5ID0gYygxLCAxLCAwLjUpKQpwCmdnc2F2ZSgicGFuZWxzL3BlYWtfYW5ub192aW9saW5fdjIucGRmIixwKQpgYGAgCg==